2017-12-30 59 views
1

私はモバイルアプリケーション用のAPIを提供するSymfonyをベースとしたモバイルアプリケーションとサーバーを持っています。Doctrineでデッドロックを処理する方法は?

ユーザーはPostのような状況があります。 PostのようなユーザーがManyToManyテーブルにこの特定のユーザーが好きなエントリを追加するのは、この特定のPostです(ステップ1)。次にPostテーブルでlikesCounterを増やします(ステップ2)。それでUserテーブルで私は(彼はPostが好きだったので)ユーザーのためのガンジーポイントを増やします(ステップ3)。

多くのユーザーが同時にPostを好きで、デッドロックが発生する状況があります(PostテーブルまたはUserテーブル)。 これを処理する方法は? Doctrine Docsでは、私はこのようなソリューションを見ることができます:

<?php 

try { 
    // process stuff 
} catch (\Doctrine\DBAL\Exception\RetryableException $e) { 
    // retry the processing 
} 

が、私はcatch部分で何をすべきでしょうか?好きなプロセス(ステップ1〜3)を3回繰り返し、失敗した場合はBadRequestをモバイルアプリケーションに戻しますか?または、他の何か?

デッドロックが発生しないようにプロセスを再構築しようとする可能性がありますが、実際にはどうすればよいか知りたいと思うかもしれません。

答えて

0

私がしたいのは、キューにすべてのお気に入りを投稿し、batch consumerを使用してそれらを消費するので、更新を1つの投稿にまとめることができます。

<?php 
 

 
for ($i = 0; $i < $retryCount; $i++) { 
 
    try { 
 
     // try updating 
 
     break; 
 
    } catch (\Doctrine\DBAL\Exception\RetryableException $e) { 
 
     // you could also add a delay here 
 
     continue; 
 
    } 
 
} 
 

 
if ($i === $retryCount) { 
 
    // throw BadRequest 
 
}

これは醜いソリューションであり、私はそれを示唆しています:

あなたはあなたの現在の実装を保つことを主張した場合、あなたは、あなた自身がこのよう提案道を行くことができます。デッドロックは、再試行または遅延の使用によって「回避」されるべきではありません。また、named locksを見て、同じ再試行システムを使用しますが、デッドロックが発生するのを待ってはいけません。

0

問題は、Symfony Entity Managerが失敗した後に、db接続が閉じられ、ORMExceptionをキャッチしても作業を続けることができないということです。

最初の良い解決策は、rabbitmqや他のキューの実装で、あなたの 'likes' asyncを処理することです。

ステップバイステップ:

  1. {type: 'like', user:123, post: 456}
  2. のようなメッセージを作成してキュー
  3. でそれを公開して、更新が回数を '好き' 消費します。

postIdに基づいてロックを取得しようとする複数のコンシューマを持つことができます。 2人の消費者が同じ投稿を更新しようとすると、そのうちの1人がロックの取得に失敗します。しかし、それは大丈夫です、あなたは後に失敗したメッセージを消費することができます。

第2の解決策は、特別なテーブルを有することである。 post_likes(userId、postId、timestamp)。エンドポイントはこのテーブル内に新しい行を同期して作成できます。そして、あなたはこのテーブルでいくつかのポストで「好き」を数えることができます。あるいは、このテーブルの投稿数を更新するcronスクリプトを書くこともできます。

関連する問題