Manifest (Manifest v0.1.0) View Source

Provides a structure for ordering operations that need to happen, and how to roll them back if they fail.

There are examples of usage in test/example_test.exs.

Link to this section Summary

Functions

Reports on the results of perform/1.

Check if any of the steps had an error.

Initializes a new t:Manifest.t().

Performs the steps in the order given to the manifest.

Rolls back each operation in case of failure.

Link to this section Types

Specs

t() :: %Manifest{
  errored: Manifest.Step.operation(),
  halt?: boolean(),
  previous: map(),
  reason: any(),
  rollbacks: [Manifest.Step.rollback()],
  steps: [Manifest.Step.t()]
}

Link to this section Functions

Link to this function

add_step(manifest, operation, work, rollback \\ &Step.safe_default_rollback/1, parser \\ &Step.default_parser/1)

View Source

Specs

Adds a Manifest.Step to the :steps key of the manifest.

True to Elixir/Erlang practices, it is prepended to the list. The list is reversed the work is actually performed.

See Manifest.Step for more information on what a step is.

Specs

digest(t()) :: {:ok, map()} | {:error, atom(), any(), map()}

Reports on the results of perform/1.

Returns an :ok tuple with the value of the :previous key which contains the results of all the steps if all steps succeeded. Otherwise it returns an :error tuple with the Manifest.Step.operation/0, as it's second element, the results of that step's Manifest.Step.work/0, and the value of the :previous field at the time of failure. (Which, since all other work is halted, means the summary of work done.) It works essentially the same as the return of Ecto.Repo.transaction/1 when given an Ecto.Multi.

Specs

errored?(t()) :: boolean()

Check if any of the steps had an error.

Specs

new() :: t()

Initializes a new t:Manifest.t().

The manifest is not customizable, so no options can be given to this function.

Specs

perform(t()) :: t()

Performs the steps in the order given to the manifest.

(Each new call of add_step/1 prepends a Manifest.Step.t/0 to the list, then the list is reversed before performing.) If a step's Manifest.Step.work/0 succeeds without returning :no_rollback in the tuple, the Manifest.Step.parser/0 finds the identifier, and a Manifest.Step.rollback/0 is defined the rollback will be added to the :rollbacks stack. If a step fails, the :halt? will activate and no further work will be performed. The :errored key will be set to the operation that triggered the failure. Whether or not the step fails, a key-value pair will be added to the :previous field. The Manifest.Step.operation/0 will be the key of that key-value pair.

TL;DR: There's three paths a step can take:

  1. It returns {:ok, term} in which case it will add a rollback to the stack.
  2. It returns {:ok, :no_rollback, term} where no rollback will be added.
  3. It returns {:error, term} which will halt the Manifest and no further steps will be performed. You can then choose to roll it all back where it will pop the functions off the stack.

See digest/1 as it provides an easier way of extracting pertinent information on what happened during this function.

Specs

rollback(t()) :: {:ok, map()} | {:error, {atom(), any()}, map()}

Rolls back each operation in case of failure.

Each Manifest.Step.t/0 that ran previous to the point of failure, defines a Manifest.Step.rollback/0 in the manifest, and didn't receive a :no_rollback in tuple that the step's Manifest.Step.work/0 returned, will be rolled back in reverse from the order the steps were performed. If any of the rollbacks fail, it stops attempting to roll back and returns an :error tuple. The error tuple has the Manifest.Step.operation/0 where it failed as it's second element, the reason as the third, and a map containing the results of all the successful roll backs up to that point.

You can also call rollback/1 on a completely successful Manifest.