Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Kadai3-2 hioki-daichi #50

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
Open

Kadai3-2 hioki-daichi #50

wants to merge 12 commits into from

Conversation

hioki-daichi
Copy link

@hioki-daichi hioki-daichi commented Sep 9, 2018

課題3-2 分割ダウンロードを行う

  • Rangeアクセスを用いる
  • いくつかのゴルーチンでダウンロードしてマージする
  • エラー処理を工夫する
    • golang.org/x/sync/errgourpパッケージなどを使ってみる
  • キャンセルが発生した場合の実装を行う

その他やったこと

  • ダミーサーバーの作成
    • GET /foo で Gopher の画像を返すような Partial Requests に対応したダミーサーバーです。
      • Range: bytes=0-99 のようなリクエストヘッダを指定してリクエストすると その範囲の content を 206 Partial Content とともに返します。
    • 起動時に以下のオプションを設定することができます。
      • -failure-rate
        • 失敗率です。例えば -failure-rate=5 を指定して実行すると、5% の確率で Internal Server Error を返すようになります。デフォルトは 0% です。
      • max-delay
        • レスポンスを返す際の遅延です。例えば -max-delay=100ms を指定して実行すると、0~100ms 遅延させてレスポンスを返すようになります。デフォルトは 1 秒のため、0 から 1 秒の間でランダムに遅延します。
      • port
        • ポート番号です。デフォルトは 8080 です。 💭ミラーサイト並列ダウンロードの実装をしやすくするためにオプションで指定できるようにしていたけれどもう満足してしまった・・
  • コマンド実行時のオプション
    • 以下のオプションを実装しました。
      • -p
        • 並列数です。指定した数に応じて並列にファイルをダウンロードします。デフォルトは 8 です。
      • -o
        • ファイルの出力先です。テストの時に tempdir に出力したかったため指定できるようにしました。デフォルトは取得先 URL のファイル名になります。
          • ※ 取得先 URL のファイル名がない場合は "index.html" になります。wget と同じ挙動です。
      • -t
        • タイムアウトです。context.WithTimeout を使いたかったため、指定できるようにしました。デフォルトは 30 秒です。
  • Ctrl+C 対応
    • Ctrl+C を実行した際に context を cancel することでそれ以降のリクエスト処理を続行させないようにしました。
      • context を cancel すると同時に、処理の過程でできたゴミデータの削除もしています。
        • var cleanFns []func()
          // for testing
          var osExit = os.Exit
          // Listen listens signals.
          func Listen(ctx context.Context, w io.Writer) (context.Context, func()) {
          ctx, cancel := context.WithCancel(ctx)
          ch := make(chan os.Signal, 2)
          signal.Notify(ch, os.Interrupt, syscall.SIGTERM)
          go func() {
          <-ch
          fmt.Fprintln(w, "\rCtrl+C pressed in Terminal")
          cancel()
          for _, f := range cleanFns {
          f()
          }
          osExit(0)
          }()
          return ctx, cancel
          }
          // CleanFunc registers clean function.
          func CleanFunc(f func()) {
          cleanFns = append(cleanFns, f)
          }
        • tempDir, err := ioutil.TempDir("", "parallel-download")
          if err != nil {
          return err
          }
          clean := func() { os.RemoveAll(tempDir) }
          defer clean()
          termination.CleanFunc(clean)
        • 💭 このゴミデータの削除をラクにするために、defer で remove されるような tempdir 内でチャンクファイルの結合までを行い、最後にそのファイルを rename して最終的な path に置くというような実装にしてみました。

DEMO

※ 上側では $ ./bin/dummy_server.go -port=8080 -max-delay=500ms -failure-rate=1 のようにしてダミーサーバーを実行しています。(レスポンス時に 0~500ms 遅延させ、1 %の確率で 500 エラーを返すようなオプション)
※ 下側では $ go run main.go -p=32 -t=10s -o=bar.png http://localhost:8080/foo.png; open bar.png のようにしてコマンドを実行し、作成されたファイルを開いています。(32 並列でタイムアウトは 10 秒、出力先は bar.png というオプション)

demo

補足

  • READMEはこちらです。
  • カバレッジはお手元の環境で以下を実行することで確認できます。(92 %程度です)
    • curl -s https://raw.githubusercontent.com/gopherdojo/dojo3/kadai3-2-hioki-daichi/kadai3-2/hioki-daichi/coverage.html -o /tmp/coverage-hioki-daichi.html && open /tmp/coverage-hioki-daichi.html

所感

Gopher道場#3終わってしばらく経ってしまいましたが、やっと満足行くものが出せました 😌
Ctrl+C 実行時は context.WithCancel を使い、 -t=30s のようなタイムアウトオプション指定時は context.WithTimeout を、リクエストの際は都度 req = req.WithContext(ctx) し、errgroup も eg, ctx := errgroup.WithContext(ctx) で context に包み、 eg.Go に渡す関数内では select { case<-ctx.Done(): で待ち受けるなど、 context をたくさん使ったことで context に慣れたような気がします。

@hioki-daichi hioki-daichi added WIP Work in Progress Kadai3-2 labels Sep 9, 2018
@hioki-daichi hioki-daichi self-assigned this Sep 15, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant