class Mara::Batch

Perform operations in batches.

@note This is not the same as a transaction. It only saves on the number

of API calls to DynamoDB.

@example Saving Multiple Records

Mara::Batch.in_batch do
  person1.save
  person2.save
end

@author Maddie Schipper @since 1.0.0

Constants

BATCH_STACK_VAR_NAME

@private

The name of the thread variable that holds the current batch spec.

Attributes

batch_id[R]

The current batch id.

@return [String]

operations[R]

@private

The queue of operations to perform on commit.

@return [Array<Array<Symbol, Hash>>]

Public Class Methods

delete_model(item) click to toggle source

@private

Perform a delete model. If there is a current batch it is added to the operation queue. If there is no current batch, this will be forwarded directly to the { Mara::Persistence}.

@param item [Hash] The model to perform the action with.

# File lib/mara/batch.rb, line 95
def delete_model(item)
  perform_for_model(:delete_model, item)
end
delete_model!(item) click to toggle source

@private

Perform a delete model. If there is a current batch it is added to the operation queue. If there is no current batch, this will be forwarded directly to the { Mara::Persistence}.

@param item [Hash] The model to perform the action with.

# File lib/mara/batch.rb, line 107
def delete_model!(item)
  perform_for_model(:delete_model!, item)
end
in_batch() { || ... } click to toggle source

Perform in a batch.

All save/destroy calls on a model will be routed into the current batch.

If there is a error raised all operations will be dropped.

If the error is a { Mara::Rollback} the batch will silently rollback. If not, it will be re-thrown after the rollback.

@yield The batch operation.

# File lib/mara/batch.rb, line 47
def in_batch
  begin_new_batch
  begin
    yield
  rescue  Mara::Rollback
    abort_current_batch
  # rubocop:disable Lint/RescueException
  rescue Exception => exception
    # rubocop:enable Lint/RescueException
    abort_current_batch
    raise exception
  else
    commit_current_batch
  end
end
new() click to toggle source

@private

Create a new batch.

# File lib/mara/batch.rb, line 160
def initialize
  @batch_id = SecureRandom.uuid
  @operations = []
end
save_model(item) click to toggle source

@private

Perform a save model. If there is a current batch it is added to the operation queue. If there is no current batch, this will be forwarded directly to the { Mara::Persistence}.

@param item [Hash] The model to perform the action with.

# File lib/mara/batch.rb, line 71
def save_model(item)
  perform_for_model(:save_model, item)
end
save_model!(item) click to toggle source

@private

Perform a save model. If there is a current batch it is added to the operation queue. If there is no current batch, this will be forwarded directly to the { Mara::Persistence}.

@param item [Hash] The model to perform the action with.

# File lib/mara/batch.rb, line 83
def save_model!(item)
  perform_for_model(:save_model!, item)
end

Private Class Methods

abort_current_batch() click to toggle source
# File lib/mara/batch.rb, line 137
def abort_current_batch
  batch_stack.pop.abort_batch
end
batch_stack() click to toggle source
# File lib/mara/batch.rb, line 125
def batch_stack
  Thread.current[BATCH_STACK_VAR_NAME] ||= []
end
begin_new_batch() click to toggle source
# File lib/mara/batch.rb, line 129
def begin_new_batch
  batch_stack <<  Mara::Batch.new
end
commit_current_batch() click to toggle source
# File lib/mara/batch.rb, line 133
def commit_current_batch
  batch_stack.pop.commit_batch
end
current_batch() click to toggle source
# File lib/mara/batch.rb, line 121
def current_batch
  batch_stack.first
end
perform_for_model(action_name, item) click to toggle source
# File lib/mara/batch.rb, line 113
def perform_for_model(action_name, item)
  if (batch = current_batch)
    batch.add(action_name, item)
  else
     Mara::Persistence.send(action_name, item)
  end
end

Public Instance Methods

abort_batch() click to toggle source

@private

Abort the batch and clear the current batch operations.

@return [void]

# File lib/mara/batch.rb, line 198
def abort_batch
  @operations = []
   Mara.instrument('batch.abort', batch_id: batch_id)
end
add(action_name, item) click to toggle source

@private

Add an item to the operation queue.

@param action_name [Symbol] The action to perform for the item. @param item [Hash] The hash of data for the action.

@return [void]

# File lib/mara/batch.rb, line 174
def add(action_name, item)
   Mara.instrument('batch.add_item', batch_id: batch_id, action: action_name, item: item) do
    operations << [action_name, item]
  end
end
commit_batch() click to toggle source

@private

Perform all the operations in the queue.

@return [void]

# File lib/mara/batch.rb, line 186
def commit_batch
   Mara.instrument('batch.commit', batch_id: batch_id) do
    execute_commit
  end
end

Private Instance Methods

execute_commit() click to toggle source
# File lib/mara/batch.rb, line 205
def execute_commit
  ops = operations.map do |action_name, item|
    case action_name
    when :save_model, :save_model!
       Mara::Persistence::CreateRequest.new(item)
    when :delete_model, :delete_model!
       Mara::Persistence::DestroyRequest.new(item)
    else
      raise "Unexpected operation action name #{action_name}"
    end
  end
   Mara::Persistence.perform_requests(
     Mara::Client.shared,
     Mara.config.dynamodb.table_name,
    ops
  )
end