2016-03-23 3 views
0

Существует 2 apis, выставленных для клиента и продавца. Оба торговца и клиента попадут в соответствующий api с тот же идентификатор транзакции .. Кто бы ни пришел первым, я должен создать запись в db с идентификатором транзакции и продавцом детали (если продавец приходит первым), а во-вторых, если клиент приходит, я должен обновить запись с информацией о клиенте с идентификатором транзакции, когда торговец создал запись.Ruby on rails Queing

Как я могу справиться с этим, приняв сразу 10 000 запросов. Он должен ответить без каких-либо проблем? Пожалуйста, дайте мне знать, как мы можем реализовать в rails и возможно ли это или нет.

Спасибо заранее ..

ответ

0

Я skidish давая это как ответ, но это звучит, как вы просто нужно, это замок. Измените таблицу, чтобы включить столбец «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):

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

Я представлю альтернативный способ справиться с этим.

Как заметил в своем ответе Камурей, блокировка - это один из способов сделать это. Вот некоторые дополнительные ресурсы:

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

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

Другой способ обработки, который будет использовать на уровне базы данных ограничений. В то время как состояние гонки уровня Rails может привести к сбою целостности данных, на уровне базы данных записи все еще вставлены один за другим (что является одной из причин, по которой запись медленнее, чем чтение).

Таким образом, вы можете просто добавить уникальное ограничение индекса в одном из полей. Поскольку вы не описали, как клиенты и торговцы соответствуют транзакции_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 

Я использую это в производстве и мы обслуживаем миллионы дб сделок без проблем. И блок спасения обычно будет выполняться только несколько раз, так как большую часть времени вы найдете запись и сразу возвращаете ее.