Hazardy przy płatnościach

Załóżmy że mam aplikacje która rozrosła się w dość spory sposób, i czasami występują hazardy przy płatnościach.

Nasza aplikacja wysyła requesty do zewnętrznego API od płatności.
Każda płatność (model Payment) zawiera pole line_item_id i należy do modelu Service.
line_item_id jest unikatowe.

Mam znaleźć lub utworzyć obiekt poprzez unikatowy klucz i zaktualizować go bez budowania nadmiarowych konstrukcji.

Mamy klasę AR

class Payment < ActiveRecord::Base belongs_to :service end
Aplikacja nie posiada obecnie żadnego mechanizmu który powodował by że była by odporna na hazardy.
Rozrosła się do stopnia w którym wiele procesów wysyła request do zewnętrznego API i można wiele requestów może uzyskać dostęp do tego samej płatności - trzeba zaprojektować rozwiązanie które spowoduje że nie będą występować zduplikowane obiekty od płatności w całym systemie.
Jako DB jest używany PostgreSQL i można wykorzystać jego feature do pomocy. :wink:

Wiele procesów/wątków może uzyskać dostęp do tej samego samego obiektu płatności.
Jeśli 2 lub więcej procesów chce zaktualizować płatność, powinna się zrobić taka jakby kolejka i lock.
Jeden proces robi update, drugi czeka -> Pierwszy proces zakończył update, drugi go zaczyna itd

Jeśli płatność nie istnieje to pierwszy proces ją tworzy, a inne procesy na nią czekają.

Jak narazie mam 1 pomysł na zrobienie czegoś takiego (delayed job) oraz metoda typu

[code=ruby]Payment.update_with(:line_item_id => line_item_id, :service_id => service_id) do |payment|

update

end[/code]
Da się to jakoś lepiej zrobić?

PS Ten ‘task’ wydawał mi się dość ambitny, dlatego postanowiłem złapać nieco perspektywy od bardziej doświadczonych osób.


Innym słowy chcesz założyć Lock na bazie.

A do zapobiegania duplikatów na bazie używa się unikalnych indexów: http://www.postgresql.org/docs/8.0/static/indexes-unique.html

Jeszcze jedna rzecz, co to są hazardy? Jaka to nomenklatura ?

O rany julek, tyle fackupów z opisanym przez ciebei rozwiązaniem że nawet za bardzo nie wiem gdzie zacząć.

Po pierwsze każde APi płatności jakie znam pozwala(a część nawet wymaga!) podania unikatowego identyfikatora transakcji - wystarczy go wiec zapisać i nie ma możliwości żeby płatność trafiłą do złej transakcji.

@paneq
Dzięki za odpowiedź(i).

Hazardy to takie moje wytłumaczenie, chodzi o to żeby nie doszło do sytuacji takiej w które 2 wątki/procesy zaczynają robić update danego obiektu i końcowy stan nie jest poprawny (drugi wątek powinien zaczekać na pierwszy wątek).

Masz na myśli delayed job?

Warto jeszcze zaznajomić się z poziomami izolacji transakcji.