2016-03-23 28 views
0

顧客と販売者の両方に公開されている2つのapisがあります。商人と顧客の両方がそれぞれと同じトランザクションIDでそれぞれのapiを打つでしょう。最初に来る人は、トランザクションIDと商人詳細(マーチャントが最初に来る場合)、2番目に顧客が来たら、マーチャントがレコードを作成したトランザクションIDを持つ顧客の詳細でレコードを更新する必要があります。Ruby on rails Queing

どのようにすれば、一度に10,000リクエストのヒットを受け入れることができますか?それは何の問題もなく返信する必要がありますか? railsにどのように実装すればいいのか教えてください。

は、私は答えとしてこれを与えskidishだけど、あなただけのロックである必要があるように聞こえる...事前に

答えて

0

、ありがとうございました。 'owned_by'(または類似のもの)という列を含むようにテーブルを変更します。

インスタンスがレコードを変更する必要があるときはいつでも、それはこのようアップデートを発行します:

UPDATE table_name SET owned_by = IF(owned_by IS NULL, 'uniq_id', owned_by) WHERE id = 1; 

それはチェックの間でロックされていた場合にはIF文がロックを盗むからそれを保持します。

次に、uniq_idが現在のスレッドuniq_idに設定されている場合、書き込みが安全であることが分かります。そうでなければ、レコードロックが解放されるまでインクリメントと再クエリでスリープします。ロックなしで何かができる場合は、そのフィールドを無視してください。ワークフローは次のようになります(sudo code)。

def uniq_id 
    rand() #probably want something better here 
end 

def trylock_row 
    "UPDATE table_name SET owned_by = IF(owned_by IS NULL, '#{uniq_id}', owned_by) WHERE id = #{id};" 
end 

def release_lock 
    "UPDATE table_name SET owned_by = IF(owned_by == '#{uniq_id}', NULL, owned_by) WHERE id = #{id};" 
end 

def reget_row 
    "SELECT * FROM table_name WHERE id = #{id}" 
end 

def issue_update something 
    r = self 
    while(r.owned_by != uniq_id){ 
    if r.owned_by.nil? 
     trylock_row 
     r = reget_row 
     break if r.owned_by == uniq_id 
    end 
    sleep(0.25) #arbitrary, keep it small 
    r = reget_row 
    } 
    #issue_updates 
    release_lock #Really should be in a ensure block just in case 
end 
0

これを処理する別の方法を提供します。

Camwayが彼の答えで述べたように、ロックはそれを行うための一つの方法です。それは、データベースレベルの制約を使用することでしょう処理する

http://thelazylog.com/understanding-locking-in-rails-activerecord/

https://www.leighhalliday.com/avoid-race-conditions-with-postgres-locks

別の方法:ここではいくつかの余分なリソースがあります。 Railsレベルの競合状態によってデータの整合性が失われる可能性がありますが、データベース・レベルでは、レコードは1つずつ挿入されます(書き込みが読み取りよりも遅い理由の1つです)。

フィールドのいずれかにユニークなインデックス制約を追加するだけで済みます。顧客と販売者がtransaction_idとどのように一致するかを記述していないので、制約を追加するフィールドを指定することはできません。しかし、あなたはこのようなものを持つことができます:

def find_or_create 
    # pseudocode here 
    transaction = Transaction.find_by_condition(...) 
    return transaction if transaction 

    Transaction.create!(...) 
rescue ActiveRecord::RecordNotUnique, ActiveRecord::RecordInvalid => e 
    log_error 
    retry 
end 

私はこれを生産で使用しており、何百万というdbトランザクションを問題なく扱っています。レスキューブロックは、通常、レコードを見つけて直ちに返すので、通常は数回実行されます。