class Novel::Saga

Attributes

executor[R]
workflow[R]

Public Class Methods

new(name:, workflow:, executor:) click to toggle source
# File lib/novel/saga.rb, line 9
def initialize(name:, workflow:, executor:)
  @name = name

  @workflow = workflow
  @executor = executor
end

Public Instance Methods

call(params: {}, saga_id: SecureRandom.uuid) click to toggle source
# File lib/novel/saga.rb, line 16
def call(params: {}, saga_id: SecureRandom.uuid)
  start_result = executor.start_transaction(saga_id, params, workflow.activity_steps.first)
  return start_result if start_result.value![:status] == :waiting

  context, saga_state = start_result.value![:context]

  if context.success?
    activity_flow_result = executor.call_activity_flow(context, saga_state, workflow.activity_steps_from(context.last_competed_step))

    activity_flow_result.or do |error_result|
      compensation_result = sync_compensation_result_for(error_result[:context], saga_state, error_result)

      Failure(status: :saga_failed, compensation_result: compensation_result, context: compensation_result.value![:context])
    end
  else
    compensation_steps = workflow.compensation_steps_from(context.last_competed_compensation_step)
    compensation_result = executor.call_compensation_flow(context, saga_state, compensation_steps)

    Failure(status: :saga_failed, compensation_result: compensation_result, context: compensation_result.last.value![:context])
  end
end

Private Instance Methods

sync_compensation_result_for(context, saga_state, error_result) click to toggle source
# File lib/novel/saga.rb, line 40
def sync_compensation_result_for(context, saga_state, error_result)
  if workflow.next_compensation_step(context.last_competed_compensation_step)[:async]
    # TODO: saga_state.wait
    Success(error_result: error_result, context: context)
  else
    executor.call_compensation_flow(context, saga_state, workflow.compensation_steps_from(context.last_competed_compensation_step))
  end
end