ようへいの日々精進XP

よかろうもん

cron + α が欲しい時には ts(Task Spooler) のご利用をご検討下さいというメモ

おひさしブリーフ、かっぱです。

tl;dr

下図のように cron ジョブで定期的にスクリプトを生成して実行させようとした時、スクリプト完了する前に次の cron ジョブが走ってスクリプトが生成されて、そのスクリプトが実行されてしまうような状況に遭遇してどうしたもんかなと悩んでいたら ts というツールを見つけたので試してみた。

f:id:inokara:20160807074518p:plain


memo

ts とは

スクリプトやコマンドを ts コマンド経由で実行することで、それらをジョブとしてキューに放り込んで順次実行してくれるツール。冒頭の構成に ts を加えると下図のようになり、cron の開始時間とスクリプトの実行時間の依存関係は切り離される。

f:id:inokara:20160807082925p:plain

導入

CentOS 6 に導入するにはソースコードを取得してビルドする必要がある。

$ cat /etc/redhat-release
CentOS release 6.7 (Final)

$ sudo yum install gcc
$ wget http://vicerveza.homeunix.net/~viric/soft/ts/ts-0.7.6.tar.gz
$ tar zxvf ts-0.7.6.tar.gz
$ cd ts-0.7.6
$ make
$ mkdir ~/bin
$ cp ts ~/bin/ts

サンプル

以下のような雑なシェルスクリプトを cron で実行させる。

$ cat demo.sh
#!/bin/sh

DATE=`date +%s`
echo "echo $DATE && sleep 300" > /tmp/test.sh.$DATE
${HOME}/bin/ts logger -t ts_demo "スクリプトを作成しました"
sleep 3
logger -t ts_demo "スクリプトを実行します"
${HOME}/bin/ts sh /tmp/test.sh.$DATE
${HOME}/bin/ts -d logger -t ts_demo "スクリプトの実行が完了しました"

$ crontab -l
*/3 * * * * /home/centos/demo.sh >/dev/null 2>&1

暫く放置してから ts コマンド(ts -l でも同等)を実行すると以下のように ts コマンド経由で実行したコマンド(スクリプト)がジョブとしてキューイングされている。

$ ts
ID   State      Output               E-Level  Times(r/u/s)   Command [run=1/1]
0    running    /tmp/ts-out.b5xJat                           sh /tmp/test.sh.1470470326
1    queued     (file)                                       [0]&& logger -t ts_demo スクリプトの実行が完了しました
2    queued     (file)                                       logger -t ts_demo スクリプトを作成しました
3    queued     (file)                                       sh /tmp/test.sh.1470470342
4    queued     (file)                                       [3]&& logger -t ts_demo スクリプトの実行が完了しました

さらに暫く放置してからジョブ一覧を確認すると...

$ ts -l
ID   State      Output               E-Level  Times(r/u/s)   Command [run=1/1]
6    running    /tmp/ts-out.FSSSnL                           sh /tmp/test.sh.1470470581
7    queued     (file)                                       [6]&& logger -t ts_demo スクリプトの実行が完了しました
8    queued     (file)                                       logger -t ts_demo スクリプトを作成しました
9    queued     (file)                                       sh /tmp/test.sh.1470470761
10   queued     (file)                                       [9]&& logger -t ts_demo スクリプトの実行が完了しました
11   queued     (file)                                       logger -t ts_demo スクリプトを作成しました
12   queued     (file)                                       sh /tmp/test.sh.1470470941
13   queued     (file)                                       [12]&& logger -t ts_demo スクリプトの実行が完了しました
14   queued     (file)                                       logger -t ts_demo スクリプトを作成しました
15   queued     (file)                                       sh /tmp/test.sh.1470471121
16   queued     (file)                                       [15]&& logger -t ts_demo スクリプトの実行が完了しました
0    finished   /tmp/ts-out.b5xJat   0        300.00/0.00/0.00 sh /tmp/test.sh.1470470326
1    finished   /tmp/ts-out.js0Oq6   0        0.00/0.00/0.00 [0]&& logger -t ts_demo スクリプトの実行が完了しました
2    finished   /tmp/ts-out.6Jjrf6   0        0.00/0.00/0.00 logger -t ts_demo スクリプトを作成しました
3    finished   /tmp/ts-out.fotDb6   0        300.00/0.00/0.00 sh /tmp/test.sh.1470470342
4    finished   /tmp/ts-out.8y6fdL   0        0.00/0.00/0.00 [3]&& logger -t ts_demo スクリプトの実行が完了しました
5    finished   /tmp/ts-out.lMTR8K   0        0.00/0.00/0.00 logger -t ts_demo スクリプトを作成しました

finished となっているのは完了したジョブ。logger で吐いているログを見ると...

$ sudo tail -f /var/log/messages
Aug  6 08:03:04 ip-xxx-xx-xx-xx ts_demo: スクリプトを実行します
Aug  6 08:03:49 ip-xxx-xx-xx-xx ts_demo: スクリプトの実行が完了しました
Aug  6 08:03:49 ip-xxx-xx-xx-xx ts_demo: スクリプトを作成しました
Aug  6 08:06:04 ip-xxx-xx-xx-xx ts_demo: スクリプトを実行します
Aug  6 08:08:49 ip-xxx-xx-xx-xx ts_demo: スクリプトの実行が完了しました
Aug  6 08:08:49 ip-xxx-xx-xx-xx ts_demo: スクリプトを作成しました
Aug  6 08:09:04 ip-xxx-xx-xx-xx ts_demo: スクリプトを実行します
Aug  6 08:12:04 ip-xxx-xx-xx-xx ts_demo: スクリプトを実行します
Aug  6 08:13:49 ip-xxx-xx-xx-xx ts_demo: スクリプトの実行が完了しました
Aug  6 08:13:49 ip-xxx-xx-xx-xx ts_demo: スクリプトを作成しました

ts の操作

以下は ts の主な操作。

  • ジョブの一覧確認
$ ts -l
  • 完了したジョブをジョブ一覧から削除
$ ts -C
  • ジョブの一括削除(タスクスプーラーサーバープロセスを kill する)
$ ts -K
  • 前のジョブが完了したら実行する

以下のように -d オプションをつけてジョブを登録することで、${command-1} が正常終了したら ${command-2} が実行される。

$ ts ${command-1}
$ ts -d ${command-2}
  • ジョブの標準出力を確認
$ ts -t ${JOB_ID}

その他、以下が ts のヘルプ。

$ ts -h
usage: ts [action] [-ngfmdE] [-L <lab>] [-D <id>] [cmd...]
Env vars:
  TS_SOCKET  the path to the unix socket used by the ts command.
  TS_MAILTO  where to mail the result (on -m). Local user by default.
  TS_MAXFINISHED  maximum finished jobs in the queue.
  TS_MAXCONN  maximum number of ts connections at once.
  TS_ONFINISH  binary called on job end (passes jobid, error, outfile, command).
  TS_ENV  command called on enqueue. Its output determines the job information.
  TS_SAVELIST  filename which will store the list, if the server dies.
  TS_SLOTS   amount of jobs which can run at once, read on server start.
  TMPDIR     directory where to place the output files and the default socket.
Actions:
  -K       kill the task spooler server
  -C       clear the list of finished jobs
  -l       show the job list (default action)
  -S [num] get/set the number of max simultaneous jobs of the server.
  -t [id]  "tail -n 10 -f" the output of the job. Last run if not specified.
  -c [id]  like -t, but shows all the lines. Last run if not specified.
  -p [id]  show the pid of the job. Last run if not specified.
  -o [id]  show the output file. Of last job run, if not specified.
  -i [id]  show job information. Of last job run, if not specified.
  -s [id]  show the job state. Of the last added, if not specified.
  -r [id]  remove a job. The last added, if not specified.
  -w [id]  wait for a job. The last added, if not specified.
  -k [id]  send SIGTERM to the job process group. The last run, if not specified.
  -u [id]  put that job first. The last added, if not specified.
  -U <id-id>  swap two jobs in the queue.
  -B       in case of full queue on the server, quit (2) instead of waiting.
  -h       show this help
  -V       show the program version
Options adding jobs:
  -n       don't store the output of the command.
  -E       Keep stderr apart, in a name like the output file, but adding '.e'.
  -g       gzip the stored output (if not -n).
  -f       don't fork into background.
  -m       send the output by e-mail (uses sendmail).
  -d       the job will be run only if the job before ends well
  -D <id>  the job will be run only if the job of given id ends well.
  -L <lab> name this task with a label, to be distinguished on listing.
  -N <num> number of slots required by the job (1 default).

最後に

ts の使いドコロ

  • 分散キューシステムでは無いので、一台のサーバー上でしか動かせないのは注意が必要
  • 遅延処理はしたいけど、処理の実行順序は出来るだけ守りたい場合
  • SQS や RabbitMQ 等を導入する程でもなくて、一台のサーバーで完結するようなバッチ処理

今まで知らずにすいません

本当にすいません。

福岡は Ruby に縁がある街なので、その県民として Ruby Association Certified Ruby Programmer Silver version 2.1 を受験してきた

ども、かっぱです。

tl;dr

福岡は Ruby に縁がある街だと勝手に思っているので、その県民としての義務を果たすべく Ruby Association Certified Ruby Programmer Silver version 2.1 を受験してきたのでメモ。

www.ruby.or.jp

ちなみに、福岡には以下のような Ruby の名前を冠した施設がある。

frac.jp

また、以下のような組織もある。

www.digitalfukuoka.jp

Ruby の故郷は島根県の松江かもしれないけど、第二の故郷は福岡なのかもしれない(と勝手に思っている)。


試験結果は

合否

90 点で合格。(100 点満点で 75 点以上が合格)


なんで受けたか

  • 冒頭にも書いたように福岡県民としての義務だと感じたのが一つ
  • 初老のおっさんが普通自動車免許以外にも免許が欲しかったのが一つ
  • インフラエンジニアでも Ruby 等のプログラム言語に直面する機会が増えてきたので、せめて基本は抑えておきたいと思ったのが一つ

どんな風に勉強したか

勉強した期間

  • トータルで一ヶ月分位

参考書籍

Ruby技術者認定試験合格教本 Silver/Gold対応 Ruby公式資格教科書

Ruby技術者認定試験合格教本 Silver/Gold対応 Ruby公式資格教科書

カスタマーレビューでは評価はイマイチだけど、受験に必要な知識がコンパクトに纏まっているし、模擬試験 50 問 + 基礎知識問題が 30 問ついているので、この本をザーッと一回読んで、模擬試験を解きまくった。

www.ruby.or.jp

上記に掲載されている模擬試験も同じように解きまくった。

模擬試験丸覚えにならない工夫

模擬試験を繰り返しているうちに答えを覚えてしまったので、自分なりに模擬試験の選択肢を pry で実行しながら誤った選択肢の挙動も確認するようにした。

やっぱり pry

模擬試験を解きながら、本を読みながら、掲載されているコードは出来るだけ pry で実行して結果を確認した。


最後に

ちょっとだけ...どんな感じで出題されたか

詳しくは書けないけど、こちらの「試験実施要項 」に書かれているように、主要なクラス(Array や Hash や String)の各メソッドの挙動については抑えておくべきだと思う。あと、演算子、これはかなり覚えるに苦労した...。今でも覚えられていないけど。

次は

メタプログラミングRuby」を読んでゴールド頑張りたい。

メタプログラミングRuby 第2版

メタプログラミングRuby 第2版