0

コンテキスト: 私が行っている操作の多くは、長い Web アクセスを必要とします。Web アクセスが失敗し、プロセスを再起動する必要がある場合があります。そして、プロセスを最初からやり直すのは苦痛です。

そのため、チェックポイントに対するアドホックなアプローチをいくつか書いてきました。プロセスを再起動すると、チェックポイント データが利用可能かどうかが確認され、そこから状態が再初期化されます。そうでない場合は、新しい状態が作成されます。操作の過程で、プロセスは定期的にチェックポイント データをどこかに (ファイルまたはデータベースに) 書き込みます。完了すると、チェックポイント データがクリーンアップされます。

シンプルで DRY な汎用チェックポイント メカニズムが必要です。どのように書きますか?または、すでにこれを行うモジュールはありますか? (まだ問題ではありませんが、スレッドセーフな実装には余分な星が与えられます!)

4

2 に答える 2

0

熟考した後、これを ActiveRecord 固有のものにすることにしました。ruby のensure機能と ActiveRecord のdestroyed?andchanged?メソッドを利用することで、設計はシンプルになります。

:name と :state を使用してチェックポイント モデルを定義する

# file db/migrate/xyzzy_create_checkpoints.rb
class CreateCheckpoints < ActiveRecord::Migration
  def change
    create_table :checkpoints do |t|
      t.string :name
      t.string :state
    end
    add_index :checkpoints, :name, :unique => true
  end 
end

# file app/models/checkpoint.rb
class Checkpoint < ActiveRecord::Base
  serialize :state
end

WithCheckpoint モジュールを定義する

# file lib/with_checkpoint.rb
module WithCheckpoint

  def with_checkpoint(name, initial_state, &body)
    r = Checkpoint.where(:name => name)
    # fetch existing or create fresh checkpoint
    checkpoint = r.exists? ? r.first : r.new(:state => initial_state)
    begin
      yield(checkpoint)
    ensure
      # upon leaving the body, save the checkpoint iff needed
      checkpoint.save if (!(checkpoint.destroyed?) && checkpoint.changed?)
    end
  end
end

使用例

これは、何回かの繰り返しの後にランダムに爆発するやや不自然な例です。より一般的なケースは、いずれかの時点で失敗する可能性のある長時間のネットワークまたはファイル アクセスである可能性があります。注: 「状態」が単純な整数である必要がないことを示すためだけに、状態を配列に格納します。

class TestCheck
  extend WithCheckpoint

  def self.do_it
    with_checkpoint(:fred, [0]) {|ckp|
      puts("intial state = #{ckp.state}")
      while (ckp.state[0] < 200) do
        raise RuntimeError if rand > 0.99
        ckp.state = [ckp.state[0]+1]
      end
      puts("completed normally, deleting checkpoint")
      ckp.delete
    }
  end

end

TestCheck.do_it を実行すると、何回か繰り返した後にランダムに爆発することがあります。ただし、正しく完了するまで再起動できます。

>> TestCheck.do_it
intial state = [0]
RuntimeError: RuntimeError
        from sketches/checkpoint.rb:40:in `block in do_it'
        from sketches/checkpoint.rb:22:in `with_checkpoint'
        ...
>> TestCheck.do_it
intial state = [122]
completed normally, deleting checkpoint
=> #<Checkpoint id: 3, name: "fred", state: [200]>
于 2012-05-05T05:06:59.917 に答える
0

あなたが本質的に説明しているのは、ステートマシンです。Web サービスはステートレスですが、サーバー側で何かに更新を提供するたびに状態が更新され、「チェック ポイント」として機能するため、トランザクション間または呼び出し時に「Web アクセス」間で状態を保持できます。 .

これまでにステート マシンを使用したことがない場合は、少し習得が難しいかもしれませんが、「チェック ポインティング」または「ステート」gem のリストを提供するこのページを参照してください。AASMはおそらく機能し、活発に開発されていますが、必要な機能の量に応じて、画面の右側にある選択肢のリストを見て、最適なものを確認してください。

私が知っている aasm の実稼働用途の 1 つは、複数ステップのプロセスを通じて人の進行状況を自動的に保存し、途中でやめたり、切断したり、後で戻ってきて完了したりできるようにすることです。プロセスのステップは何らかの順序で完了する必要があり、ほとんどの場合、「完了」状態が定義されています。AASMは、この種のことを処理できるはずです。

于 2012-05-02T01:02:39.300 に答える