Tarantube
Smalltalk でメッセージキュー
Smalltalk勉強会2017
合同会社ソフトウメヤ 梅澤真史
Tarantubeとは
● 永続化機能付きメッセージキュー
○ http://smalltalkhub.com/#!/~MasashiUmezawa/Tarantube
● Tarantoolのqueueモジュールのラッパー
○ わずか3クラスで作られている
■ TrTube
■ TrTubeTask
■ TrTubeOptionsBuilder
Tarantubeの例
tarantalk := TrTarantalk connect: 'taran:talk@localhost:3301'.
"FIFOのtube作成"
tube := tarantalk ensureTubeNamed: 'my_tube'.
"tubeにtaskを追加"
1 to: 10 do: [:idx | tube putTaskWith: idx asString].
"定期的にタスクを取得して実行"
tube repeatTakeTaskIfAvailable:
[:task | Transcript cr; show: {task. task data}. task done].
Tarantool
● No SQLの注目株
○ ThoughtWorks Technology RadarのAssess段階
○ ロシア製。Mail.ruで使われている
■ Heavy workloads: our use cases of Tarantool
● Tupleの永続化をサポート
○ KVSよりも構造化、RDBよりは軽量
● Luaの実行エンジンであり、Luaで拡張できる
○ queue, RDBとの接続など
● 1.8系列からLuaに加えてSQLも使える
Tarantoolのインストール
● Tarantoolの入手
○ https://tarantool.org/en/download/download.html
■ 様々なプラットフォームに対応
○ Macなら
brew install tarantool --HEAD
Tarantoolの起動
● 適当なディレクトリ(taranとか)を作成、移動し
● 3 + 4
● クライアントの接続受付
tarantool> 3 + 4
tarantool
tarantool> box.cfg{listen = 3301}
ユーザの権限設定
● 接続用ユーザの登録
box.schema.user.grant('taran', 'read,write,execute', 'universe')
box.schema.user.create('taran', {password = 'talk'})
● アクセス権限の付与
参考: SmalltalkからLuaをevalする
queueモジュールの導入
● tarantoolctlで
tarantoolctl rocks install queue
● tarantoolのコンソールからrequireすると使える
tarantool> queue = require('queue')
tarantool> queue.stats()
config.luaでの起動
● お決まりの設定を書いておくと便利
box.cfg{listen = 3301, work_dir = 'queue_db'}
box.schema.user.create('taran', {password = 'talk', if_not_exists=true})
box.schema.user.grant('taran', 'read,write,execute', 'universe', nil,
{if_not_exists=true})
queue = require('queue')
require('console').start()
tarantool config.lua
● config.luaの例
Tarantubeのインストール
● Catalog Browserから
○ 'tarantube'で検索し、"install stable version"
● あるいはMetacelloでロード
Metacello new
smalltalkhubUser: 'Pharo' project: 'MetaRepoForPharo60';
configuration: 'Tarantube';
version: #stable;
get; load.
Tarantubeの構成
● Tarantalk-Core
○ TrTube
■ いわゆるキュー
○ TrTubeTask
■ キューに積まれるタスク。
任意のデータを保持できる
○ TrTubeOptionsBuilder
■ 各種オプション指定のためのビルダー
Tubeの生成
● TrTarantalk>>connect:で接続
○ URLでユーザ名、パスワードを指定
● ensureTubeNamed:type:setting:でTubeを生成
○ ensureTybeNamed:type:で明示的に指定しない場合
シンプルなfifoキューとなる
tarantalk := TrTarantalk connect: 'taran:talk@localhost:3301'.
tube := tarantalk ensureTubeNamed: 'my_tube'.
Tubeの種類
● fifo
○ もっともシンプルなキュー
● fifottl
○ TTL(time to live), TTR(time to run), Priority, Delay などが
指定できる高機能なキュー
● utube
○ グループ化できるキュー。グループごとにfifoで処理される
● utubettl
○ utubeの高機能版 (TTL, TTR, Priority, Delay…)
● https://github.com/tarantool/queue#queue-types
Taskの投入(put)
● TrTube>>putTaskWith:setting:で投入
○ 任意のデータ、及びdelayなどのオプションを指定できる
tube putTaskWith: 'hello'.
tube putTaskWith: 'he--llo--' setting:[:opts| opts delay: 20].
Tarantubeの例 (再び)
tarantalk := TrTarantalk connect: 'taran:talk@localhost:3301'.
"FIFOのtube作成"
tube := tarantalk ensureTubeNamed: 'my_tube'.
"tubeにtaskを追加"
1 to: 10 do: [:idx | tube putTaskWith: idx asString].
"定期的にタスクを取得して実行"
tube repeatTakeTaskIfAvailable:
[:task | Transcript cr; show: {task. task data}. task done].
実行結果は...
● Transcript に以下のように表示
consoleからの状態確認
● config.lua でconsoleをstart させておく
require('console').start()
● queue.stats()
○ タスクの状態、呼び出しの状態が一覧表示される
tarantool> queue.stats()
delayを試してみる
"fifottlのtube作成"
ttlTube := tarantalk ensureTubeNamed: 'ttl_tube' type: 'fifottl'.
"tubeにtaskを追加"
ttlTube putTaskWith: 'delayed' setting: [:opts | opts delay: 10].
1 to: 10 do: [:idx | ttlTube putTaskWith: idx asString].
"定期的にタスクを取得して実行"
ttlTube repeatTakeTaskIfAvailable:
[:task | Transcript cr; show: {task. task data}. task done].
実行結果は...
● 10秒後に'delayed'のタスクが実行される
ttlを試してみる
"タスク取得を止めておく"
ttlTube stopTaking.
"取得したタスクを実行する度に2秒ほど待つようにする"
ttlTube repeatTakeTaskIfAvailable:
[:task | Transcript cr; show: {task. task data}.
2 seconds wait. task done ifFailed: [:ex | ex inspect]].
"tubeにTTLが5秒のtaskを追加"
1 to: 10 do: [:idx |
ttlTube putTaskWith: idx asString setting: [:opts | opts ttl: 5]].
実行結果は...
● 2つまで成功。3つ目はdoneに失敗
utubeで詰まりにくく
"utubeのtube作成"
uTube := tarantalk ensureTubeNamed: 'u_tube' type: 'utube'.
"偶数、奇数のグループ指定でtaskを追加"
1 to: 10 do: [:idx |
uTube putTaskWith: idx asString
setting: [:opts | opts utube: (idx rem: 2) asString]].
uTube takeTask done.
pending := uTube takeTask. "2番目をdoneにしない"
uTube repeatTakeTaskIfAvailable:
[:task | Transcript cr; show: {task. task data}. task done].
実行結果は...
● 偶数グループは詰まる
● 奇数グループが実行を続ける
buryとkick (1)
"タスクを一時退避"
pending bury.
● 偶数グループも実行される
buryとkick (2)
"一時退避していたタスクをキューに戻す"
uTube kick: 1.
● 2番目のタスクも実行される
luaでburyするには
● tarantoolctl connect 'user:pass@host:port'
○ あるいはconsoleでもよい
queue.tube.u_tube:bury(box.space.u_tube.index.status:select('r')[1][1])
● 管理用には覚えておくと便利
○ https://github.com/tarantool/queue#fields-of-the-spac
e-associated-with-each-queue
接続の解放
● TrTarantalk>>releaseで切断
● TrTarantalk class >> releaseAll
○ 全ての接続を一度に解放
tarantalk release.
TrTarantalk releaseAll.
事例は?
● ALLSTOCKER でメール送信のキューとして使用中
○ アプリサーバのPharoからのリクエストで送信メールを永続
キューにためる
○ 別のPharoがキューから取り出し、SendGrid, TwilioのAPI経
由で送信
まとめ
● Tarantubeでメッセージキューをわりと簡単に
Pharoに導入できる
○ 永続化される安心感
○ 軽量だがそれなりに高機能
● そろそろSmalltalkHubからGitHubに移動したい

Tarantubeでメッセージキューを使い倒す