クライアントからの支払いを処理する単純なサービス(C#、SQL Server、Entity Frameworkを使用)を実装しようとしています。単一の製品は、など、10回以上の日を購入することはできません)Entity Frameworkで正しい並行性/ロックメカニズムを選択する方法
コードの簡易版は、以下の通りです:私は心配です何
public void ExecutePayment(int productId, PaymentInfo paymentInfo)
{
using (var dbContext = new MyDbContext())
{
var stats = dbContext.PaymentStatistics.Single(s => s.ProductId== productId);
var limits = dbContext.Limits.Single(l => l.ProductId == productId);
int newPaymentCount = stats.DailyPaymentCount + 1;
if (newPaymentCount > limits.MaxDailyPaymentCount)
{
throw new InvalidOperationException("Exceeded payment count limit");
}
// other limits here...
var paymentResult = ProcessPayment(paymentInfo); <-- long operation, takes 2-3 seconds
if (paymentResult.Success)
{
stats.DailyPaymentCount = newPaymentCount;
}
dbContext.SaveChanges();
}
}
可能同時実行の問題です。 2つのスレッド/プロセスが同時にチェック/更新を開始しないようにする必要があります。そうしないと、統計情報が同期しなくなります。
私はこのような(this implementationを使用して、たとえば)分散ロックにメソッド全体を包む考えていた:
string lockKey = $"processing-payment-for-product-{productId}";
var myLock = new SqlDistributedLock(lockKey);
using (myLock.Acquire())
{
ExecutePayment(productId, paymentInfo);
}
しかし、このアプローチの懸念はProcessPaymentが非常に遅いことである(2-3秒)これは、同じ製品の同時支払い要求が、制限チェックが開始されるまで2〜3秒待たなければならないことを意味します。
誰もがこのケースで良いロックソリューションを提案できますか?
また、データベースに支払いを保存していますか?保留中/失敗/完全な支払いを表す支払いオブジェクトを意味します。 – Evk
@Evk、はい、現在のところ、SQL Serverはすべての種類のアプリケーションデータの唯一の格納メカニズムです –