打倒qudo with fireworq

この記事は[Wanoグループアドベントカレンダー2020](https://qiita.com/advent-calendar/2020/wano-group)の22日目の記事です。

こんにちは。アルファアーキテクト株式会社でバックエンドおじさんをやっているstk0724です。

今回はqudoを~~倒そうとしている~~リプレイスしようとしているという話です。


## qudoとは

perl製のジョブキュー(メッセージキュー?)です。

バックエンドはRDBMSとなっており、ジョブをエンキューするクライアント、ジョブを処理するワーカーからなります。

Perl Hackers Hubの紹介記事がありますので、詳しくはそちらを参照してください。

[第10回　ジョブキューで後回し大作戦―TheSchwartz，Qudo，Q4M（2）](https://gihyo.jp/dev/serial/01/perl-hackers-hub/001002)

### なぜqudoをリプレイスしたいのか

最大のモチベーションは**脱Perl**です。

というか、前述のとおり、qudoのクライアント、ワーカーはPerlで書く必要があるため、qudoが残っていると脱Perlできないのです。

(qudoのクライアント、ワーカーのバックエンドのRDBMSに対するふるまいを他の言語で実装すれば、他の言語からqudoを扱うことは可能でしょうが、まあそんなことはしたくないですよね。。。)


## fireworqとは

qudoの代わりにfireworqというジョブキュー実装の利用を検討しています。

[fireworq](https://github.com/fireworq/fireworq)

fireworqははてなで開発されたOSSです。

[GoとMySQLを用いたジョブキューシステムを作るときに考えたこと](https://blog.yuuk.io/entry/go-and-mysql-jobqueue)

fireworqのバックエンドはMySQLとなっており、fireworqのプロセスはジョブの投入を受け付けるhttpサーバーと、MySQLからジョブを取り出すディスパッチャーからなります。

fireworqのジョブは以下の2つから構成されます。

- ジョブを処理するワーカーの存在するURL
- 上記のURLにPOSTするpayload

fireworqのディスパッチャーは自身ではジョブの処理そのものは実行せず、ジョブ内で指定されたURLに対してpayloadをPOSTするという動きをします。

そのため、fireworqを利用するユーザは、ジョブを投入するためのクライアントとジョブを処理するためのhttpサーバーを用意すればいいことになります。

### fireworqだと何がうれしいのか

すぐ上で書いてるんですけど、

- クライアントはhttpリクエストができればいい
- ワーカーはhttpサーバーが建てられればいい

一般的なプログラミング言語で上記2点を満たしてない言語って存在しないと思うので、fireworqを利用するにあたっては利用言語が制限されないということになります。

(もちろん、クライアントとワーカーでそれぞれ異なる言語を利用することも可能です)

その他にも良いところがあるんですけど、詳しくはfireworqのREADMEを読んでください。

あと、はてな内でバリバリproduction環境で利用されている点と、コード規模が私でも追いきれる程度というのも大きいです。


## 他のジョブキューとか検討しなかったのか

SQSとかActiveMQとか一応検討したんですが、fireworqはqudoと同じでバックエンドがRDBMSなので、登録済みのジョブが雑にSQLで確認できる点が大きいと考え、fireworqにしました。

## 検討している構成

fireworqはdockerイメージが提供されていますので、それをbaseイメージとして、mysqlの接続情報などをよしなにした感じのdockerイメージを作ります

Dockerfileはこんなんで

``` dockerfile
FROM fireworq/fireworq:1.4.0
COPY run.sh /tmp/run.sh
ENTRYPOINT ["/bin/ash", "/tmp/run.sh"]
```

実行しているシェルスクリプトはこんなん

``` run.sh
exec /usr/local/bin/fireworq --mysql-dsn="${DB_USER}:${DB_PASSWORD}@tcp(${DB_HOST}:3306)/fireworq"
```

mysqlの接続情報はコンテナ起動時に環境変数で引き渡します。

実行環境はAWS ECSで、fireworq、ジョブを処理するサーバともにプライベートサブネットに配置します。
(インターネットからアクセスできる必要はないですからね)

fireworqにジョブを投入するクライアント側からは決まったドメイン名でアクセスできるようにしたいので、ECSのサービスディスカバリ機能を利用します。

上述のmysqlの接続情報は、parameter storeから参照するようにタスク定義します。
ちなみに[7日目の記事](https://gist.github.com/naoto243/0b79e5e7f58d5935c05e57013db87c71)はparameter storeのユースケースに関する記事となっていますので、読みましょう。

図は気が向いたら書きます(この記事, 22日当日にピンチヒッターで書いてますからね。


## fireworqのマズいところ

まだproduction投入できてなくて大した知見がないので、検証環境で動かしてて気づいたマズいところを書いておきます。

### パスワードを含むmysqlの接続情報がログに出力されてしまう

2020/12/22時点で以下のコードが存在しています

``` go
// NewDB creates an instance of DB handler.
func NewDB() (*sql.DB, error) {
	dsn := Dsn()

	log.Info().Msgf("Connecting database %s ...", dsn)
...省略...
```

https://github.com/fireworq/fireworq/blob/96dc7517b2cefcf7dc4bd0a2b31203b4dc1b8812/repository/mysql/db.go#L40

(当該コードに対してプルリク送った記事が書ければよかったんですが、年明けリリースに向けてプロジェクトが佳境を迎えており、パツっているため、無念)


## 終わりに

[17日目の記事](https://qiita.com/stk0724/items/7e3d5535e027f2cdcd48)でも書きましたが、現在広告入稿管理画面のリニューアルプロジェクトが動いており、fireworqによるqudoリプレイスはそのタイミングでリリース予定となっております。

年明けリリース予定なのですが、某サイバーパンクみたいなことにならないか緊張しており、夜も6時間しか眠れません。

fireworqに興味を持ったそこのあなた、アルファアーキテクトでは絶賛エンジニア募集中です。

- [wantedly](https://www.wantedly.com/companies/alpha-architect)
- [Green](https://www.green-japan.com/job/99699)

## 参考リンク

- [fireworq](https://github.com/fireworq/fireworq)
- [GoとMySQLを用いたジョブキューシステムを作るときに考えたこと](https://blog.yuuk.io/entry/go-and-mysql-jobqueue)
- [第10回　ジョブキューで後回し大作戦―TheSchwartz，Qudo，Q4M（2）](https://gihyo.jp/dev/serial/01/perl-hackers-hub/001002)