おすすめ書籍はじめにこんにちは。今回、Goシリーズ第6回目を担当させていただきます!今回はGoでバックグラウンドでジョブを処理する「gocraft/work」を使用して、常駐プロセスでのジョブ処理について説明します。公式のREADMEに挙げられていますが、その中からピックアップして紹介します。実行速度が速く、かつ効率的に動作するとのことです。Benchmarksによると、他の3ライブラリと比較して、最も早いことが分かります。プロセスがクラッシュしてもジョブが失われない。Middlewareという仕組みがあり、ジョブ実行時に呼び出され、メトリック計測・ログ出力に適しています。様々な特徴がありますが、サンプルを動かしながら主要な機能を説明していきます。workを使えるようにするRedisのインストールworkによるジョブ実行のバックエンドには、Redisの通知があるため、Redisをインストールする必要があります。インストールしている人は飛ばしていただいて構いません。macOSの人はHomeBrewでインストールできます。get」コマンドを使用し、今回使用するworkと、依存するredigoのredisをインストールします。github.com/gomodule/redigo/redisこれで準備完了です。Enqueue〜ジョブ実行まで公式のサンプルを参考に、Enqueue〜ジョブ実行まで作ってみました。Enqueue側とジョブ実行は、別のGoプロジェクトとしました。Enqueue側ほぼ公式サンプルですが、1回実行するごとに、1回エンキューするシンプルなものです。(日本語でのコメントを記入しました。新規Enqueuerを作成します。namespaceです。ジョブをエンキューします。ジョブ名は"send_email"で、addressやsubjectといったパラメータを付加しています。新規Enqueuerを作成します。namespaceです。ジョブをエンキューします。ジョブ名は"send_email"で、addressやsubjectといったパラメータを付加しています。{log.Fatal(err)}}「Redisプールの作成」はRedis周りの設定になります。この場合はエンキュー側の設定になるため、エンキューされる契機が多ければ、MaxActiveやMaxIdleの設定を上げても良いと思います。こちらの設定については、こちらの記事が参考になります。あとは、main関数で、ジョブに名前を付け、データを指定することができます。ジョブ実行側こちらは起動させておいて、エンキューされたらジョブを実行する側になります。ジョブワーカーを管理するWorkerPoolを作成します。シグナルを受信すると待機をやめ、ここまで進むので、WorkerPoolを止めます。ジョブワーカーを管理するWorkerPoolを作成します。シグナルを受信すると待機をやめ、ここまで進むので、WorkerPoolを止めます。nil}main関数の流れを簡単に説明します。Workerプールを作成し、ミドルウェアの設定、ジョブと関数のマッピングといった設定を行います。設定が完了したら、Workerプールを開始します。その後は、OSシグナルで終了するまで待機させておくことにより、その間エンキューを受け付けて処理を実行させることが可能になります。ミドルウェア用の関数や、ジョブ処理用の関数は、Context構造体のメソッドとなっています。run」すると、ビルド実行側にログが表示されることが分かります。(あらかじめRedisは起動しておいてください)また、ジョブ実行側はOSシグナルが無い限り待機し続けるため、Enqueue側を何度も実行すれば、ジョブ実行側にその分ログが出力されます。バックエンドはRedisなので、先にEnqueue側を何度か実行しておけば、ジョブ実行側が後から立ち上がった時に、Enqueueされた分だけジョブが実行されます。ContextworkにおけるContextは実装者が自由に定義できる構造体ですが、WorkerPoolに必要です。フィールドは空でも、様々なフィールドがあっても構いません。Middlewareやジョブ実行用のメソッドはこのContextに実装する必要があります。そのため、Middlewareやジョブ実行時に、Contextのフィールドを書き換えることも可能です。MiddlewareMiddlewareはジョブ実行時に、任意のコードを実行できる機能です。ジョブでは本質的に行いたい機能を、Middlewareではログ取りや計測といった、付属的かつ各ジョブでの共通機能、といった使い分けが可能です。ジョブ実行中のタスクキルジョブ実行側では、Redisからの通知を待機するため、「signal.Notify()」を使用して、OSシグナルを受信するまで待機するように実装しました。シグナルを受信すると待機をやめ、ここまで進むので、WorkerPoolを止めます。シグナルを受信すると待機をやめ、ここまで進むので、WorkerPoolを止めます。syscall.SIGHUPのいずれかを受信すると、signalChanに受信され、5行目以降の処理に移ります。その後はそのまま「pool.Stop()」でWorkerPoolを止めますが、実行中のジョブに関しては、完了を待ってから終了されます。-HUP」でシグナル送信を行うと、ジョブが完了するまでは、プロセスキルされません。CronライクなスケジュールPeriodicallyEnqueueを使用すると、WorkerPoolを使用して、Cronライクにジョブの定期実行ができます。GoのCron構文仕様は下記が参考になります。*」の場合は、毎時実行されます。)PeriodicallyEnqueueは、先ほどのEnqueueとは異なり、WorkerPoolに対して設定します。シグナルを受信すると待機をやめ、ここまで進むので、Workersを止めます。シグナルを受信すると待機をやめ、ここまで進むので、Workersを止めます。nil}実行すると、毎秒SampleProcess()が呼び出され、ログ出力されます。Enqueueした時のRedisについて最初のサンプルでEnqueueした直後に、redis-cliで実際の値を確認してみました。"send_email"これを読んでみると、「設定した名前空間:jobs:設定したジョブ名」をキーにして、JSON文字列でEnqueueされたジョブ情報が入っています。(リスト型)また、「設定した名前空間:known_jobs」には、上記でEnqueueしたジョブ名が入っています。こちらはセット型なので、ジョブ名は重複せずに管理されていることが分かります。上記を踏まえ、RubyからEnqueueするプログラムを作成してみました。'send_email')今回は、先ほどのサンプルのEnqueueをRubyで呼び出してみました。workで動作させることが目的であるため、Redisに格納するキーと値は、workの仕様に基づいたものになります。valueのidは、12バイトの乱数をHex文字列で渡します。tは現在時刻をタイムスタンプで渡します。Redisを使用しているので、Enqueueする側の自由度はかなり高いですね。WebUI同じくgocraftが提供している「workwebui」を導入すると、ジョブの状況について、WebUIで可視化できます。install」することで使用可能になります。github.com/gocraft/work/cmd/workwebui下記コマンドでWebUIが起動します。-listen=":5040"起動できたらブラウザから「http://localhost:5040/」にアクセスしてください。先ほどのサンプルをWebUIで見てみるこのように、実行中のジョブを確認することができます。処理中のジョブ、再施行されたジョブ、スケジュールされた(Cronライクな)ジョブ等、各ジョブの状況ごとに表示することができます。さいごにworkはシンプルなインターフェースでありながら、柔軟性の高いライブラリでした。Redisを使用しているため、エンキュー側は何でもよく、ワーカー側もContextへの実装により様々なジョブ処理が可能です。Goでバックグラウンドジョブを実装する際は、ぜひ使って見てください。Go記事の連載などは、こちらをご覧ください。コメントをキャンセルメールアドレスが公開されることはありません。コメント名前メールアドレスサイト上に表示された文字を入力してください。私たちは無料アプリもリリースしています、ぜひご覧ください。下記のアイコンから無料でダウンロードできます。