2016-06-01 6 views
3

Ich muss eine große Anzahl von Datensätzen in Batches verarbeiten. Und jede Charge sollte in einer eigenen Transaktion verarbeitet werden. Gibt es eine Möglichkeit, jeden Stapel in eine Transaktion zu verpacken und alle Datensätze im Stapel gleichzeitig zu sperren?Schienen find_in_batches mit Verriegelung

Model.scheduled_now.lock.find_in_batches do |batch| 
    model_ids = batch.map(&:id) 
    Model.update_all({status: 'delivering'}, {"id IN (?)" , model_ids}) 

    # creates and updates other DB records 
    # and triggers background job 
    perform_delivery_actions(batch) 
end 

Hat SELECT FOR UPDATE in diesem Beispiel begeht nach jeder Charge Transaktion? Oder ich muss interne Transaktionsblock und sperren Datensätze manuell in jedem Batch (was bedeutet, eine weitere Abfrage)?

Der Grund, dass ich nicht äußere Transaktionsblock setzen möchte, ist, dass ich jeden Batch einzeln, nicht eine ganze Sache auf einmal begehen will.

Antwort

0

landete ich meine eigene Implementierung find_in_batches_with_lock:

def find_in_batches_with_lock(scope, user, batch_size: 1000) 
    last_processed_id = 0 
    records = [] 
    begin 
    user.transaction do 
     records = scope.where("id > ?", last_processed_id) 
        .order(:id).limit(batch_size).lock.all 
     next if records.empty? 
     yield records 
     last_processed_id = records.last.id 
    end 
    end while !records.empty? 
end