Webとバックグラウンドワーカープロセスで構成されるアプリケーション用のPostgres(9.5)DBがあります。異なるPostgresセッションからのロックとロック解除
HTTPリクエストPOST /items/123/steps
を受け取った場合、Webアプリケーションはアイテム123に「ワークフローステップ」を実行して戻るためのバックグラウンドタスクをキューに入れます。アイテムは、目標は、バックグラウンドタスクは、アイテムのロックを解除するまでPOST /items/123/steps
に後続の要求が拒否されるように、何らかの方法で処理するための項目123をロックすることであるPostgresのitems
テーブル内の行に対応したID値123
と列を有しています123作業を完了した後。
同様に、GET /items/123
への要求は、アイテム123がロックされていることを示す属性を返して、バックグラウンドタスクがアイテムをロック解除するまでUIが現在処理中のアイテムを表示できるようにする必要があります。
バックグラウンドタスクがそのキューから取得されるまでに遅延が生じる可能性があるため、バックグラウンドタスクが実行を開始するときにアイテム123をロックするのに十分ではありません。アイテム123は、バックグラウンドタスクが完了するまで最初のPOST
Webリクエストからロックされたものとしてマークされ、バックグラウンドタスクが選択される前に入ってくるWebリクエストに対してロックされたアイテムとして表示されます。
可能であれば、これを達成するためにPostgresを使用したいと思います。しかし、私が見つけたのオプションが動作していないようです:トランザクションが終了したときに
- Row locksは私のWebハンドラが戻ったときに発生する、解放されています。バックグラウンドタスクは、異なるトランザクションでその作業を実行します。だから私はアイテム123に
SELECT FOR UPDATE
を実行することはできません。 - セッションレベルadvisory lockは、Webプロセスから取得した場合、Webプロセスとワーカープロセスをそれぞれ処理するため、ワーカープロセスからロックを解除できません独自のPostgresセッションを確立する。
items
にlocked
列を追加し、バックグラウンドタスクに戻っFALSE
にし、WebエンドポイントでTRUE
に設定し、:
私はアドホックロック機構を実装することでこの問題を回避することができます。それを行う標準的な方法が存在する場合は、私はむしろそれを行うだろう。
追加情報:これはPythonプロジェクトで、(Flask)Webアプリケーションと(Celery)バックグラウンドタスクの両方からPostgresにアクセスするためにSQLAlchemyを使用しています。私のために機能するこれらのツールで目標を達成するためのもう一つの実証済みの方法がある場合。