Module: OneMoreTime

Defined in:
lib/one_more_time.rb,
lib/one_more_time/version.rb,
lib/one_more_time/idempotent_request.rb

Defined Under Namespace

Classes: Error, IdempotentRequest, RequestInProgressError, RequestMismatchError

Constant Summary collapse

VERSION =
'0.1.0'

Class Method Summary collapse

Class Method Details

.start_request!(idempotency_key:, request_path: nil, request_body: nil) ⇒ Object



12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/one_more_time.rb', line 12

def start_request!(idempotency_key:, request_path: nil, request_body: nil)
  IdempotentRequest.create!(
    idempotency_key: idempotency_key,
    locked_at: Time.current,
    request_path: request_path,
    request_body: request_body,
  )
rescue ActiveRecord::RecordNotUnique
  # Our UNIQUE constraint was violated, so a request with the given idempotency
  # key already exists. Use the highest transaction isolation level to atomically
  # load that request record and mark it as "locked".
  # Similar to Rails create_or_find_by, the race condition here is if another
  # client deleted the request record exactly at this point. For this specific
  # model there is basically no risk of that happening.
  serializable_transaction do
    existing_request = IdempotentRequest.find_by(idempotency_key: idempotency_key, locked_at: nil)
    validate_incoming_request!(existing_request, request_path, request_body)
    existing_request.update!(locked_at: Time.current) unless existing_request.finished?
    existing_request
  end
end