Я пробую много новых идей (DDD, Event Sourcing и CQRS) и оцениваю RethinkDB как потенциальное хранилище данных для событий домена. В DDD агрегат - это набор объектов, которые работают вместе для обеспечения определенного поведения. Каждый агрегат - это граница транзакции / согласованности. Корень агрегата - это объект, который предоставляет API и скрывает внутреннюю реализацию.
Для сохранения агрегата обычно рекомендуется использовать оптимистическую блокировку. Идея состоит в том, чтобы иметь атрибут номера версии в агрегате, и когда приходит время сохранять агрегат, мы проверяем, чтобы версия агрегата в базе данных соответствовала версии агрегата, который был прочитан / обновлен в приложении. Это гарантирует, что пока никто не изменил агрегат, и предотвращает перезапись других изменений.
Очевидно, эта проверка версии не может происходить просто на уровне приложения (подумайте о сценарии с несколькими серверами приложений). Приложению требуется поддержка из хранилища данных для выполнения атомарных обновлений с учетом этого номера версии.
Вот простая реализация с использованием Ruby API RethinkDB.
Я создал таблицу под названием "кандидаты" с одной записью
"id": "6b3b57a7-3ba8-4322-873e-1d6c8333daae" ,
"name": "Homer Simpson" ,
"updated_at": Mon Dec 28 2015 12:05:40 GMT+05:30 ,
"version": 1
Вот пример кода теста, который я дважды запускал параллельно.
require 'rethinkdb'
include RethinkDB::Shortcuts
conn = r.connect(:host => 'localhost',
:port => 28015,
:db => 'test')
def update_applicant(conn, current_version)
result = r.table('applicants').get('6b3b57a7-3ba8-4322-873e-1d6c8333daae').update{ |applicant|
r.branch(
applicant['version'].eq(current_version),
{updated_at: Time.now, version: current_version + 1},
{}
)
}.run(conn)
fail 'optimistic locking failure' if result['unchanged'] == 1
rescue => e
puts "optimistic locking failure: #{current_version}"
current_version = r.table('applicants').get('6b3b57a7-3ba8-4322-873e-1d6c8333daae').run(conn)['version']
retry
end
(1..100).each { |version| update_applicant(conn, version) }
conn.close
Кажется, это работает, но я хочу убедиться, что при таком подходе в производственной среде не будет условий гонки и других проблем. Я предполагаю, что обновление - это атомарная операция, и использование ветки в обновлении по-прежнему сохраняет ее атомарностью.
Я ищу некоторые подтверждения и предложения от разработчиков / пользователей RethinkDB. Спасибо.