class Synapse::UnitOfWork::NestableUnitOfWork

Partial implementation of a unit of work that can be nested

This implementation provides common actions that will be needed for nestable units of work, such as registration with the unit of work provider and nested commit and rollback operations

@abstract

Public Class Methods

new(provider) click to toggle source

@param [UnitOfWorkProvider] provider @return [undefined]

# File lib/synapse/uow/nesting.rb, line 13
def initialize(provider)
  @inner_units = Array.new
  @provider = provider
  @started = false
end

Public Instance Methods

commit() click to toggle source

Commits this unit of work

All reigstered aggregates that have not been registered as stored are saved in their respective repositories, buffered events are sent to their respective event buses, and all registered listeners are notified of the commit.

After the commit (successful or not), the unit of work is unregistered and cleans up any resources it acquired. The effectively means that a rollback is done if the unit of work failed to commit.

@api public @raise [RuntimeError] If unit of work hasn't been started yet @return [undefined]

# File lib/synapse/uow/nesting.rb, line 32
def commit
  unless started?
    raise 'Unit of work has not been started yet'
  end

  begin
    notify_prepare_commit
    store_aggregates

    unless @outer_unit
      perform_commit
      stop
      perform_cleanup
    end
  rescue => cause
    perform_rollback cause
    stop

    unless @outer_unit
      perform_cleanup
    end

    raise cause
  ensure
    clear
  end
end
rollback(cause = nil) click to toggle source

Clears this unit of work of any buffered changes

Any buffered events and registered aggregates are discarded and any registered unit of work listeners are notified of the rollback.

@api public @param [Error] cause @return [undefined]

# File lib/synapse/uow/nesting.rb, line 68
def rollback(cause = nil)
  begin
    if started?
      @inner_units.each do |inner_unit|
        @provider.push inner_unit
        inner_unit.rollback cause
      end
      perform_rollback cause
    end
  ensure
    finalize_rollback
  end
end
start() click to toggle source

Starts the unit of work, preparing it for aggregate registration

@api public @raise [RuntimeError] If unit of work has already been started @return [undefined]

# File lib/synapse/uow/nesting.rb, line 87
def start
  if started?
    raise 'Unit of work has already been started'
  end

  perform_start

  if @provider.started?
    # This is a nested unit of work
    @outer_unit = @provider.current

    if NestableUnitOfWork === @outer_unit
      @outer_unit.register_inner_unit self
    else
      # Outer unit is not aware of inner units, hook in with a listener
      @outer_unit.register_listener OuterCommitUnitOfWorkListener.new self, @provider
    end
  end

  @provider.push self
  @started = true
end
started?() click to toggle source

Returns true if this unit of work has been started

@api public @return [Boolean]

# File lib/synapse/uow/nesting.rb, line 114
def started?
  @started
end

Protected Instance Methods

commit_inner_units() click to toggle source

Commits all registered inner units of work. This should be invoked after events have been dispatched and before any listeners are notified of the commit.

@return [undefined]

# File lib/synapse/uow/nesting.rb, line 173
def commit_inner_units
  @inner_units.each do |inner_unit|
    if inner_unit.started?
      inner_unit.perform_inner_commit
    end
  end
end
notify_cleanup() click to toggle source

Notifies listeners that this unit of work is cleaning up

@abstract @return [undefined]

# File lib/synapse/uow/nesting.rb, line 141
def notify_cleanup
  raise NotImplementedError
end
notify_prepare_commit() click to toggle source

Notifies listeners that this unit of work is preparing to be committed

@abstract @return [undefined]

# File lib/synapse/uow/nesting.rb, line 149
def notify_prepare_commit
  raise NotImplementedError
end
perform_cleanup() click to toggle source

Executes logic required to clean up this unit of work

@private @return [undefined]

# File lib/synapse/uow/nesting.rb, line 194
def perform_cleanup
  @inner_units.each do |inner_unit|
    inner_unit.perform_cleanup
  end

  notify_cleanup
end
perform_commit() click to toggle source

Executes logic required to commit this unit of work

@abstract @return [undefined]

# File lib/synapse/uow/nesting.rb, line 124
def perform_commit
  raise NotImplementedError
end
perform_inner_commit() click to toggle source

Commits this unit of work as an inner unit of work

@private @return [undefined]

# File lib/synapse/uow/nesting.rb, line 206
def perform_inner_commit
  @provider.push self

  begin
    perform_commit
  rescue => cause
    perform_rollback cause
  end

  clear
  stop
end
perform_rollback(cause = nil) click to toggle source

Executes logic required to rollback this unit of work

@abstract @param [Error] cause @return [undefined]

# File lib/synapse/uow/nesting.rb, line 133
def perform_rollback(cause = nil)
  raise NotImplementedError
end
perform_start() click to toggle source

Executes logic required when starting this unit of work

@abstract @return [undefined]

# File lib/synapse/uow/nesting.rb, line 157
def perform_start
  raise NotImplementedError
end
register_inner_unit(inner_unit) click to toggle source

Registers a unit of work nested in this unit of work

@private @param [UnitOfWork] inner_unit @return [undefined]

# File lib/synapse/uow/nesting.rb, line 186
def register_inner_unit(inner_unit)
  @inner_units.push inner_unit
end
store_aggregates() click to toggle source

Storages aggregates registered with this unit of work

@abstract @return [undefined]

# File lib/synapse/uow/nesting.rb, line 165
def store_aggregates
  raise NotImplementedError
end

Private Instance Methods

clear() click to toggle source

@return [undefined]

# File lib/synapse/uow/nesting.rb, line 232
def clear
  @provider.clear self
end
finalize_rollback() click to toggle source

@return [undefined]

# File lib/synapse/uow/nesting.rb, line 222
def finalize_rollback
  unless @outer_unit
    perform_cleanup
  end

  clear
  stop
end
stop() click to toggle source

@return [undefined]

# File lib/synapse/uow/nesting.rb, line 237
def stop
  @started = false
end