• 作成:

conduitのMonadResource mをIOに変換する方法がわからない

前回出したpull requestに返信

awsパッケージは出来る子でした, 大容量のファイルのS3へのアップロードが出来なくなりました, yesodにpull requestを出しました - ncaq

前回yesod develstack build--fast消して欲しいというpull requestを提出しました. remove the --fast flag from stack build executed by yesod devel by ncaq · Pull Request #1442 · yesodweb/yesod

これにレスがついていたので返信します. 即座にレスポンスが帰ってきましたが, pull requestを開いた後寝たため1日経っての返信になります. 時差を感じる.

google翻訳で十分理解できる平易な英語で助かりました.

そしてgoogle翻訳で返信を書く. SVOで完結するだけの文章ならともかく, ある程度複雑な文章になるとgoogle翻訳を使わないと全く書けない… 文法というより語彙力の問題なのかな?

原文

レスポンスに感謝します.

@psibi 私は問題の発生源は特定できていません. しかし, 多分, 問題があるとするなら, conduitのバグではなく, ByteStringの問題だと思います. 前に私はyesod-testで大きいサイズのファイルをたくさん投稿するプログラムを書いたことがあります. 最適化を無効にした(-O0)時のみ, 投稿後にメモリが回収されずにOOM-killerが動くことになりました. その時は, まだyesod develはstackを使わずにbuildしていたので, cabalファイルの最適化オプションをデフォルトに戻して, 対処しました.

@paul-rouse 私はcabalファイルでのghc-options: -Oが, stack build--fastで上書きされてしまうと考えていました. それを確かめようと思って,

私はstack build --fastされるとcabalファイルでの最適化オプションは無効化されると思っていました. それを確かめようとメモリリークを再現させようとしてみたのですが, 今やってみたら再現しなくなりました…

再現性が確かじゃない問題を元にpull requestを建てて, ごめんなさい, このpull requestは閉じます.

何もわからなくなった

私はstack build --fastするとcabalの記述に関わらず-O0になると思っていて, それを確かめようとメモリリーク問題を再現させようと思ったら再現しなくなった… もう何もわからない…

フロントエンド側のfetchがエラーになってしまう問題を解決

とりあえず, 100MBレベルのファイルのアップロードにサーバ側では成功するのに, フロントエンド側ではfetchがNetwork Errorを送信する問題に手をつけてみることにしました.

サーバーサイドでは

POST /2/file/new
  Accept: application/json
  Status: 200 OK 145.737839s

で200 OKを返しているのに, フロントエンドではTypeError: NetworkError when attempting to fetch resource.エラーになってしまう.

firefoxのネットワークタブを見ると, 応答は空になっている.

とりあえずエラーの文章でググッてみたところ, fetchのリポジトリで同じようなissueがあったのを発見しました.

TypeError: NetworkError when attempting to fetch resource - firefox issue · Issue #310 · github/fetch

fetchのpolyfillが悪いのかな… でもfirefoxでは動かないはずだよな…? と思いながら, とりあえずfetchのpolyfillを削除してみます. しかし当然ながら状況は変わりませんでした.

ここのissueコメントにself-signed certとか書かれていたので, 自己署名したhttps://localhost:3443/でテストしていたのが悪いのかと思ってhttpでテストしてみる.

そうするとちゃんと200の応答を待ってくれるようになりました.

redditにも同じような書き込みがありました. Fetch api not working in firefox addon : firefox

firefoxのbugとして登録されてないかなと思ってbugzillaどこからアクセスするんだっけと思ってWhat to do and what not to do in Bugzilla | MDNを見たらバグがめっちゃバクと書いてあってめっちゃウケた(直した).

冷静にredditの投稿を見なおしたら, 1346447 - Fetch api not working within addonへのリンクが貼られていた. しかし, この投稿ではCORSヘッダーの問題であるとして扱われていました. 私の案件は全てhttps://localhost:3443/で扱っているのでクロスオリジンは関係ないはずなんですよね…

バグ報告を送るべきか? うーん, 前回yesodで失敗しただけに気後れがしますね… 要は自己署名証明書を使わずに開発時は平文で, 本番時は本物の証明書を使えば良い問題で, 実害がほぼないものを多大なコストをかけて報告する気にもならない…

conduitのMonadResource mをIOに変換する方法がわからない

効率のために

requestBodySourceChunked :: Source IO ByteString -> RequestBody
  	-- Defined in ‘Network.HTTP.Client.Conduit’

λ> :t fileSource fileInfo
fileSource fileInfo :: MonadResource m => Source m ByteString

をストリームを全部取得しない方法で渡したくて数日悩んでいた.

普通にやると当然ながら型が合わない.

<interactive>:1:28-46: error:
     No instance for (MonadResource IO)
        arising from a use of fileSource     In the second argument of ($)’, namely fileSource fileInfo      In the expression: requestBodySourceChunked $ fileSource fileInfo

無理なのでは?

requestBodySourceChunkedのソースを見てみると, RequestBodyStreamChunked . srcToPopperIOなので, srcToPopperIOではなくsrcToPopperResource :: MonadResource m => Source m ByteString -> GivesPopper ()を自作できればなんとかなるのではと思った. 無理だった, 何もわからない.

MonadResource m => Source m ByteStringRequestBodyに変換する方法あると思うんですけどね… 私には作れなかった…

メモリを爆発させないで大容量ファイルのアップロードを実現する方法

  • アップロードだけgoofysを使う(敗北宣言)
  • ユーザのブラウザとS3を直接通信させる
  • インスタンスのメモリサイズを増やす(物理で殴る)
  • 一度fileMoveでテンポラリファイルを作成して, Network.HTTP.Client.streamFileで新しいストリームを作成する

今日はあまりにも無だった

ここ数日はうまく行かなくて行ったり戻ったりしていたけれど, 一応コードは書いていた.

今回はブラウザのバグ調べとかやってただけでほとんどコードを書けなかった. 無すぎる.

本当はもう少しやろうと思ってたけどプロファイリングを取ってみようとしてビルドしなおしてみたらメモリ8GBを使いきってPCが止まってしまったので今日はもうやめた. いい加減新しいPCを組みたいな, Ryzenをsegv問題さえなければ買っていたのだが.