ruote - implementing a storage を訳してみた


(2012-04-01) オレオレ訳。後半は力尽きてかなりいい加減。

----

## [ストレージの実装](http://ruote.rubyforge.org/implementing_a_storage.html)

Ruote は、メモリ上とファイルシステム上の二種類のストレージを持つ。[その他のストレージも利用可能][1]であるが、それぞれ長所、短所がある。

[1]: http://ruote.rubyforge.org/configuration.html#storage

格納するオブジェクト（式、ワークアイテム、エラー、スケジュール、...）に応じて異なるストレージを選択する複合型のストレージもある。

独自のストレージを実装する必要がある場合もある。このページは助けになるべきである。（[メーリングリスト][2]上で叫んでいない場合）

[2]: http://groups.google.com/group/openwferu-users

ストレージの実装は、ストレージ インターフェースに従う必要がある。

### 少し歴史を
ストレージは、ruote 2.1.x の核心である。

    engine = Ruote::Engine.new(Ruote::Worker.new(ThatStorage.new(info)))
      # or
    engine = Ruote::Engine.new(ThatStorage.new(info))

ワーカーとエンジンはストレージが必要とする。それらは、共有ストレージを介して連携する。

Ruote は永続性を必要とする。プロセスは、エンジンよりも寿命が長い場合がある。エンジンがダウンした場合、プロセスはストレージに格納される。ワーカーが復帰すると、プロセスは再開されなければならない。

Ruote 2.1.x の複数ワーカーは、ワーカーが互いに上書きや削除するのを防止する必要性をもたらした。

### ドキュメント

Ruote 2.1.x のストレージは、[CouchDB][3] に強く影響を受けている。特に、ドキュメントとバージョンの概念に影響を受けている。

[3]: http://couchdb.apache.org/

Ruote は全てのデータをドキュメントとして表現する。ドキュメントは [JSON][4] シリアライズ可能なハッシュである。“_id” 、“type” と “_rev” を項目として持つ。

[4]: http://json.org/

‘type’ は、“expressions” 、“errors” 、“workitems” 、“schedules” のような文字列である。

‘_id’ は、ドキュメント識別子である。

#### ドキュメント タイプ

ドキュメントには、7+1 種類のタイプがある。

<table>
    <tr>
        <th>タイプ</th>
        <th>説明</th>
    </tr>
    <tr>
        <td>expressions</td>
        <td>プロセス インスタンスの部品</td>
    </tr>
    <tr>
        <td>msgs</td>
        <td>expressions からの/への &#8216;messages&#8217;</td>
    </tr>
    <tr>
        <td>schedules</td>
        <td>後に処理するためにスケジュールされた msgs</td>
    </tr>
    <tr>
        <td>errors</td>
        <td>プロセス実行中に発生した errors</td>
    </tr>
    <tr>
        <td>variables</td>
        <td>エンジン グローバルな変数</td>
    </tr>
    <tr>
        <td>configurations</td>
        <td>エンジンのコンフィグレーション</td>
    </tr>
    <tr>
        <td>workitems</td>
        <td><a href="part/storage_participant.html">StorageParticipant</a> ワークアイテム</td>
    </tr>
    <tr>
        <td><em>history</em></td>
        <td>（<a href="https://github.com/jmettraux/ruote/blob/master/lib/ruote/log/storage_history.rb">Ruote::StorageHistory</a>を使っている場合）</td>
    </tr>
</table>

### 一貫性

Ruote は複数のドキュメントを確保する。ストレージの実装が排他的更新を提供できない場合、単一の[ワーカー][5]に制限される。

[5]: http://rdoc.info/gems/ruote/Ruote/Worker

ワーカーの詳細については [コンフィグレーション ページ][6] を参照のこと。

[6]: http://ruote.rubyforge.org/configuration.html

### インターフェース

    #--
    # 主なメソッド
    #++
     
    # ドキュメントの格納
    #
    # opts:
    # ... TODO ...
    #
    # 戻り値:
    # * true ドキュメントが削除されていた場合
    # * a document バージョン（rev）が変更された場合
    # * nil 保存が成功した場合
    #
    def put(doc, opts={})
    end
     
    # ドキュメント タイプとキー（_id）によるドキュメントの取得
    #
    def get(type, key)
    end
     
    # ドキュメントの削除
    #
    # 戻り値:
    # * true 既に削除済みの場合
    # * a document 与えられたドキュメントのバージョン（rev）が現在のバージョンと異なる場合
    #   document
    # * nil 削除が成功した場合
    #
    def delete(doc)
    end
     
    # 特定のタイプの複数のドキュメントを取得する
    #
    # 入力:
    # - key が指定されない場合、全てのドキュメントを返す
    # - Array(key) にドキュメントの _id がマッチするものを返す
    #
    # opts:
    # [:descending]    _id で降順でソートする
    # [:count]         件数を返す
    # [:skip]          X 件スキップする
    # [:limit]         X 件に制限する
    #
    # 戻り値:
    # * An Integer (:count が指定された場合)
    # * An array of documents
    #
    def get_many(type, key=nil, opts={})
    end
     
    # 指定されたドキュメント タイプの _id のリストを返す
    #
    def ids(type)
    end
     
    #--
    # 補助的なメソッド
    #++
     
    # 全ての msgs 、schedules 、errors 、expressions と workitems を削除する
    #
    # It's used mostly when testing workflows, usually when cleaning the
    # engine/storage before a workflow run.
    #
    def clear
    end
     
    # ストアをクリアする
    #
    def purge!
    end
     
    # 新しいドキュメント タイプを追加する。いくつかのストレージでは必要
    #
    def add_type(type)
    end
     
    # 指定されたタイプのドキュメントを削除する
    #
    def purge_type!(type)
    end

### モデルとしての実装

実装の例。 [hash_storage.rb][7]

[7]: http://github.com/jmettraux/ruote/blob/master/lib/ruote/storage/hash_storage.rb

### テスト

ストレージの実装は、ユニットテストと機能テストを実施されるべきだ。複数ワーカーで利用される場合、同時テストも実施すべきだ。

テストは、ruote/ ディレクトリから実行される。“redis” や “sequel” といった実装名を持つ拡張子を渡すと、テストは自動的に行われる。

このセクションの残りでは、“ruote-pasta” という実装名で、ruote-pasta/ ディレクトリに格納したと仮定する。

ストレージ実装は、“new_storage” メソッドを含む test/functional_connection.rb を提供する必要がある。これは、テストのためにストレージをセットアップするための ruote テストスイートを含む。[ruote-redis][8] や [ruote-sequel][9] の functional_connection.rb を参照のこと。

[8]: https://github.com/jmettraux/ruote-redis/blob/master/test/functional_connection.rb
[9]: https://github.com/jmettraux/ruote-sequel/blob/master/test/functional_connection.rb

#### ユニット テスト

ruote のユニットテストにおいて、ストレージのテスト関連はこれだけである。

    $ ruby test/unit/storage.rb -- --pasta

このテストをグリーンにすることが、ストレージ開発の最初の目標だ。

#### 機能テスト

ストレージ実装は全ての機能テストを通過すべきだ。

    $ ruby test/functional/test.rb -- --pasta

いくつかのダングリングテストに困難がある場合、[メーリングリスト][10] を参照のこと。

[10]: http://ruote.rubyforge.org/lists.html

#### 同時テスト（複数のワーカー）

複数のワーカーが稼働しているように ruote ストレージをテストする 3つのテストがある。それらは test/functional/ の下にあり、“ct_” が先頭についている。

ct_ テストを200回実行しても失敗しなければ、複数ワーカーで問題ないといえる。

    $ ./test/looper.sh test/functional/ct_0_concurrence.rb -- --pasta 200
    $ ./test/looper.sh test/functional/ct_1_iterator.rb -- --pasta 200
    $ ./test/looper.sh test/functional/ct_2_cancel.rb -- --pasta 200

これらのテストはワーカーの間で衝突を起こす。