Class: AceMQ::AMQP::Patterns::SagaResult

Inherits:
Object
  • Object
show all
Defined in:
lib/acemq/amqp/patterns/saga.rb

Overview

What a saga did.

Returned rather than raised, because a failed saga is not an exceptional condition to a caller that has to decide what happens next — and because the interesting part is not the exception but #unresolved, the list of things that could not be undone.

Frozen, like Envelope, for the same reason: it describes something that has already happened, and a report that could be edited after the fact is not a report.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(saga:, completed:, failed_at: nil, failure: nil, unresolved: []) ⇒ SagaResult

Returns a new instance of SagaResult.



57
58
59
60
61
62
63
64
# File 'lib/acemq/amqp/patterns/saga.rb', line 57

def initialize(saga:, completed:, failed_at: nil, failure: nil, unresolved: [])
  @saga = saga
  @failed_at = failed_at
  @failure = failure
  @completed = completed.dup.freeze
  @unresolved = unresolved.dup.freeze
  freeze
end

Instance Attribute Details

#completed ⇒ Object (readonly)

The steps that ran, in order, before the failure.



41
42
43
# File 'lib/acemq/amqp/patterns/saga.rb', line 41

def completed
  @completed
end

#failed_at ⇒ Object (readonly)

The step whose action raised, or nil when every step ran.



35
36
37
# File 'lib/acemq/amqp/patterns/saga.rb', line 35

def failed_at
  @failed_at
end

#failure ⇒ Object (readonly)

What it raised, or nil.



38
39
40
# File 'lib/acemq/amqp/patterns/saga.rb', line 38

def failure
  @failure
end

#saga ⇒ Object (readonly)

What the saga is called.



32
33
34
# File 'lib/acemq/amqp/patterns/saga.rb', line 32

def saga
  @saga
end

#unresolved ⇒ Object (readonly)

The steps whose compensation raised.



44
45
46
# File 'lib/acemq/amqp/patterns/saga.rb', line 44

def unresolved
  @unresolved
end

Class Method Details

.compensated_run(saga, failed_at, failure, completed, unresolved) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



52
53
54
55
# File 'lib/acemq/amqp/patterns/saga.rb', line 52

def self.compensated_run(saga, failed_at, failure, completed, unresolved)
  new(saga: saga, failed_at: failed_at, failure: failure,
      completed: completed, unresolved: unresolved)
end

.completed_run(saga, completed) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



47
48
49
# File 'lib/acemq/amqp/patterns/saga.rb', line 47

def self.completed_run(saga, completed)
  new(saga: saga, completed: completed)
end

Instance Method Details

#compensated? ⇒ Boolean

Whether a step failed and the earlier ones were undone.

Returns:

  • (Boolean)


70
# File 'lib/acemq/amqp/patterns/saga.rb', line 70

def compensated? = !@failed_at.nil?

#complete? ⇒ Boolean

Whether every step ran.

Returns:

  • (Boolean)


67
# File 'lib/acemq/amqp/patterns/saga.rb', line 67

def complete? = @failed_at.nil?

#to_s ⇒ Object



82
83
84
85
86
87
88
# File 'lib/acemq/amqp/patterns/saga.rb', line 82

def to_s
  return "SagaResult{#{@saga} completed: #{@completed.join(" -> ")}}" if complete?

  trailer = @unresolved.empty? ? "" : ", UNRESOLVED #{@unresolved.join(", ")}"
  "SagaResult{#{@saga} failed at #{@failed_at}, compensated " \
    "#{@completed.join(", ")}#{trailer}}"
end

#unresolved? ⇒ Boolean

Whether anything was left in a state nobody intended.

This is the flag to alert on. Everything else a saga reports is recoverable by construction; these are real-world effects that happened, were meant to be undone, and were not. Nothing else in the system knows about them, no retry will resolve them, and a person has to. Java spells it hasUnresolved(); the has_ is dropped here because Ruby says the same thing with the question mark.

Returns:

  • (Boolean)


80
# File 'lib/acemq/amqp/patterns/saga.rb', line 80

def unresolved? = !@unresolved.empty?