BackEnd

Go言語 gocraft/workを使って常駐プロセスでジョブを処理させる

投稿日:2018年10月17日 更新日:

はじめに

こんにちは。カイザーです。今回、Goシリーズ第6回目を担当させていただきます!
今回はGoでバックグラウンドでジョブを処理する「gocraft/work」を使用して、常駐プロセスでのジョブ処理について説明します。(以下workと呼びます)
https://github.com/gocraft/work

workの特徴

公式のREADMEに挙げられていますが、その中からピックアップして紹介します。

  • 実行速度が速く、かつ効率的に動作するとのことです。Benchmarksによると、他の3ライブラリと比較して、最も早いことが分かります。
  • プロセスがクラッシュしてもジョブが失われない。
  • Middlewareという仕組みがあり、ジョブ実行時に呼び出され、メトリック計測・ログ出力に適しています。
  • cronライクなスケジュールでジョブをエンキューすることも可能

様々な特徴がありますが、サンプルを動かしながら主要な機能を説明していきます。

workを使えるようにする

Redisのインストール

workによるジョブ実行のバックエンドには、Redisの通知があるため、Redisをインストールする必要があります。もうインストールしている人は飛ばしていただいて構いません。
macOSの人はHomeBrewでインストールできます。

Go用のライブラリインストール

「go get」コマンドを使用し、今回使用するworkと、依存するredigoのredisをインストールします。

これで準備完了です。

Enqueue〜ジョブ実行まで

公式のサンプルを参考に、Enqueue〜ジョブ実行まで作ってみました。
また、Enqueue側とジョブ実行は、別のGoプロジェクトとしました。

Enqueue側

ほぼ公式サンプルですが、1回実行するごとに、1回エンキューするシンプルなものです。
(日本語でのコメントを記入しました。)

「Redisプールの作成」はRedis周りの設定になります。この場合はエンキュー側の設定になるため、エンキューされる契機が多ければ、MaxActiveやMaxIdleの設定を上げても良いと思います。
こちらの設定については、こちらの記事が参考になります。

あとは、main関数で、ジョブに名前を付け、データを指定することができます。

ジョブ実行側

こちらは起動させておいて、エンキューされたらジョブを実行する側になります。

main関数の流れを簡単に説明します。
まず、Workerプールを作成し、ミドルウェアの設定、ジョブと関数のマッピングといった設定を行います。
設定が完了したら、Workerプールを開始します。
その後は、OSシグナルで終了するまで待機させておくことにより、その間エンキューを受け付けて処理を実行させることが可能になります。

ミドルウェア用の関数や、ジョブ処理用の関数は、Context構造体のメソッドとなっています。(後述のContextで説明します)

一通りの流れを試してみるには、まずジョブ実行側を「go run」しておき、後からEnqueue側を「go run」すると、ビルド実行側にログが表示されることが分かります。(あらかじめRedisは起動しておいてください)

また、ジョブ実行側はOSシグナルが無い限り待機し続けるため、Enqueue側を何度も実行すれば、ジョブ実行側にその分ログが出力されます。

バックエンドはRedisなので、先にEnqueue側を何度か実行しておけば、ジョブ実行側が後から立ち上がった時に、Enqueueされた分だけジョブが実行されます。

Context

workにおけるContextは実装者が自由に定義できる構造体ですが、WorkerPoolに必要です。
フィールドは空でも、様々なフィールドがあっても構いません。
また、Middlewareやジョブ実行用のメソッドはこのContextに実装する必要があります。
そのため、Middlewareやジョブ実行時に、Contextのフィールドを書き換えることも可能です。

Middleware

Middlewareはジョブ実行時に、任意のコードを実行できる機能です。
ジョブでは本質的に行いたい機能を、Middlewareではログ取りや計測といった、付属的かつ各ジョブでの共通機能、といった使い分けが可能です。

ジョブ実行中のタスクキル

ジョブ実行側では、Redisからの通知を待機するため、「signal.Notify()」を使用して、OSシグナルを受信するまで待機するように実装しました。

signalがos.Interrupt, os.Kill, syscall.SIGHUPのいずれかを受信すると、signalChanに受信され、5行目以降の処理に移ります。
その後はそのまま「pool.Stop()」でWorkerPoolを止めますが、実行中のジョブに関しては、完了を待ってから終了されます。

そのため、ジョブの実行中(今回の場合は10秒待機中)に「control+c」や「 kill -9」、「kill -HUP」でシグナル送信を行うと、ジョブが完了するまでは、プロセスキルされません。

Cronライクなスケジュール

PeriodicallyEnqueueを使用すると、WorkerPoolを使用して、Cronライクにジョブの定期実行ができます。
GoのCron構文仕様は下記が参考になります。
https://godoc.org/github.com/robfig/cron#hdr-CRON_Expression_Format

例えば、「0 0 * * * *」の場合は、毎時実行されます。
(フィールドは、それぞれ秒、分、時、日、曜日を表します。)

PeriodicallyEnqueueは、先ほどのEnqueueとは異なり、WorkerPoolに対して設定します。

実行すると、毎秒SampleProcess()が呼び出され、ログ出力されます。

Enqueueした時のRedisについて

最初のサンプルでEnqueueした直後に、redis-cliで実際の値を確認してみました。

これを読んでみると、「設定した名前空間:jobs:設定したジョブ名」をキーにして、JSON文字列でEnqueueされたジョブ情報が入っています。(リスト型)
また、「設定した名前空間:known_jobs」には、上記でEnqueueしたジョブ名が入っています。こちらはセット型なので、ジョブ名は重複せずに管理されていることが分かります。
上記を踏まえ、RubyからEnqueueするプログラムを作成してみました。
(「$ gem install redis」が必須です)

今回は、先ほどのサンプルのEnqueueをRubyで呼び出してみました。workで動作させることが目的であるため、Redisに格納するキーと値は、workの仕様に基づいたものになります。
valueのidは、12バイトの乱数をHex文字列で渡します。tは現在時刻をタイムスタンプで渡します。
Redisを使用しているので、Enqueueする側の自由度はかなり高いですね。

WebUI

同じくgocraftが提供している「workwebui」を導入すると、ジョブの状況について、WebUIで可視化できます。

workwebuiの導入〜起動

「go get」した後、「go install」することで使用可能になります。

下記コマンドでWebUIが起動します。

起動できたらブラウザから「http://localhost:5040/」にアクセスしてください。

先ほどのサンプルをWebUIで見てみる


このように、実行中のジョブを確認することができます。処理中のジョブ、再施行されたジョブ、スケジュールされた(Cronライクな)ジョブ等、各ジョブの状況ごとに表示することができます。

さいごに

workはシンプルなインターフェースでありながら、柔軟性の高いライブラリでした。
Redisを使用しているため、エンキュー側は何でもよく、ワーカー側もContextへの実装により様々なジョブ処理が可能です。
Goでバックグラウンドジョブを実装する際は、ぜひ使って見てください。

Go記事の連載などは、こちらをご覧ください。

おすすめ書籍

スターティングGo言語  Goプログラミング実践入門 標準ライブラリでゼロからWebアプリを作る impress top gearシリーズ  みんなのGo言語[現場で使える実践テクニック]  Go言語でつくるインタプリタ

blog-page_footer_336




blog-page_footer_336




-BackEnd
-,

執筆者:


comment

メールアドレスが公開されることはありません。

CAPTCHA


関連記事

js

Moment Timezoneを使ってJavaScriptで日付を変換する

1 はじめに2 Moment Timezone2.1 セットアップ2.2 使用例3 Moment Timezoneの機能3.1 タイムゾーンの一覧を表示する3.2 現在のタイムゾーンを表示する3.3 ...

rails

【Puma】アプリサーバのチューニング

1 はじめに2 チューニングで注意する項目3 子プロセスの数3.1 最低3つの子プロセスを割り当てる3.2 最大子プロセス数3.3 CPUコア数と子プロセス数3.4 なぜPumaの子プロセス数を増やす ...

PHPerだけどKotlinを勉強したって良いよね その1〜クラス編〜

1 はじめに2 インターフェース2.1 基本2.2 デフォルト実装付メソッド2.3 同じメソッド名を持つ複数のインターフェース3 修飾子3.1 open3.2 abstract4 可視性修飾子5 さい ...

rails

Ruby、Railsの時間に関するメソッドを使用してみた

はじめに 普段PHPのお仕事をしています、tonnyです。 半年程前からRuby on Railsの勉強を始めました。 今回はよく使う時間に関するメソッドついてまとめたいと思います。 目次 1 はじめ ...

laravel logo

Laravelの基礎知識

1 はじめに2 Laravelの概要2.1 学習コストが低い2.2 Symfonyがベース2.3 DIを積極的に活用している3 ディレクトリ構成3.1 app3.2 bootstrap3.3 conf ...

フォロー

follow us in feedly

blog-page_side_responsive

東京改造計画(NewsPicks Book)
2018年10月
 123456
78910111213
14151617181920
21222324252627
28293031 

アプリ情報

私たちは無料アプリもリリースしています、ぜひご覧ください。 下記のアイコンから無料でダウンロードできます。