2016-03-23 48 views
0

Es gibt 2 Apis für Kunden und Händler. Sowohl Händler als auch Kunde werden ihre jeweiligen API mit gleichen Transaktions-ID .. Wer zuerst kommt, sollte ich den Datensatz in db mit Transaktions-ID und Händler erstellen Details (wenn Händler zuerst kommt) und zweitens, wenn Kunde kommt, sollte ich den Datensatz mit Kundendetails mit Transaktions-ID aktualisieren, wo Händler den Datensatz erstellt hat.Ruby on rails Queing

Wie kann ich damit umgehen, indem ich 10.000 Anfrage Hits auf einmal akzeptiert. Es sollte ohne irgendein Problem antworten? Bitte lassen Sie mich wissen, wie können wir in rails implementieren und ist es möglich oder nicht.

Vielen Dank im Voraus ..

Antwort

0

Ich bin skidish dies als eine Antwort zu geben, aber es klingt wie Sie nur eine Sperre brauchen, ist. Ändern Sie Ihre Tabelle so, dass sie eine Spalte mit dem Namen "owned_by" (oder etwas Ähnliches) enthält.

Jedes Mal, wenn die Instanz einen Datensatz ändern muss, hat es ein Update wie diese Ausgabe:

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

Die IF-Anweisung hält sie stehlen das Schloss, wenn es zwischen den Prüfungen eingesperrt wurde.

Dann requery für die Zeile, und wenn die uniq_id auf die aktuellen Threads uniq_id festgelegt ist, dann wissen Sie, dass Sie sicher sind zu schreiben, andernfalls müssen sie in Schritten und requery schlafen, bis die Datensätze freizugeben. Wenn etwas ohne eine Sperre durchgeführt werden kann, muss dieses Feld ignoriert werden. Der Arbeitsablauf könnte so aussehen (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

Ich werde eine alternative Möglichkeit bieten, damit umzugehen.

Wie Camway in seiner Antwort erwähnt, ist Sperren eine Möglichkeit, es zu tun. Hier sind einige zusätzliche Ressourcen:

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

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

Ein anderer Weg, dies zu umgehen würde Datenbankebene Constraint werden. Während die Race-Bedingung auf der Rails-Ebene dazu führen kann, dass die Datenintegrität fehlschlägt, werden Datensätze auf Datenbankebene immer noch nacheinander eingefügt (was einer der Gründe dafür ist, dass Schreiben langsamer ist als Lesen).

So können Sie einfach eine eindeutige Indexeinschränkung für eines der Felder hinzufügen. Da Sie nicht beschrieben haben, wie Kunden und Händler mit der Transaktions-ID übereinstimmen, kann ich nicht feststellen, in welches Feld die Einschränkung eingefügt werden soll. Aber Sie könnten etwas wie folgt haben:

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 

Ich benutze dies in der Produktion und wir bedienen Millionen von DB-Transaktionen ohne Problem. Und der Rettungsblock wird in der Regel nur ein paar Mal ausgeführt, da Sie den Rekord meistens finden und sofort zurückgeben.