Banzai
A pipeline library for Elixir providing a token-based pattern for sequential function execution with automatic error handling.
Why "Banzai"? The name comes from the Banzai Pipeline, the legendary surf reef break on the North Shore of Oahu, Hawaii — one of the most famous wave pipelines in the world.
Banzai implements a workflow pattern where a token (a map or struct) is passed through a series of steps (functions) that transform it. Each step receives the token, performs its operation, and returns an updated token. If any step fails, execution stops immediately and the error is returned.
Installation
Add banzai to your list of dependencies in mix.exs:
def deps do
[
{:banzai, "~> 0.1.0"}
]
endQuick Start
defmodule CalculateTotal do
use Banzai
embedded_schema do
field :value, :integer
end
def perform(params) do
%__MODULE__{}
|> new(params)
|> step(fn token -> {:ok, Map.put(token, :value, token.value + 10)} end)
|> step(fn token -> {:ok, Map.put(token, :value, token.value * 2)} end)
|> step(fn token -> {:ok, Map.put(token, :value, token.value + 5)} end)
|> run()
end
end
CalculateTotal.perform(%{})
# => {:ok, %{value: 25}}How It Works
- Create a token (map or struct) that holds your pipeline state
-
Add steps that transform the token — each returns
{:ok, updated_token}or{:error, reason} - Run the pipeline — steps execute in order, stopping at the first error
defmodule ProcessOrder do
use Banzai
embedded_schema do
field :order_id, :string
# internal token fields
field :total, :integer
field :charged, :boolean
embeds_one :order, Order
end
def perform(params) do
%__MODULE__{}
|> new(params)
|> step(&fetch_order/1)
|> step(&calculate_total/1)
|> step(&charge_customer/1)
|> run()
end
defp fetch_order(%__MODULE__{} = token) do
case Orders.get(token.order_id) do
nil -> {:error, :order_not_found}
order -> {:ok, %__MODULE__{token | order: order}}
end
end
defp calculate_total(%__MODULE__{} = token) do
{:ok, %__MODULE__{token | total: Order.total(token.order)}
end
defp charge_customer(%__MODULE__{} = token) do
case Billing.charge(token.order.customer_id, token.total) do
:ok -> {:ok, %__MODULE__{token | charged: true}
{:error, reason} -> {:error, reason}
end
end
endError Handling
When a step returns {:error, reason}:
- Execution stops immediately — subsequent steps are skipped
- The error is logged with context (action ID, step index)
{:error, reason}is returned to the caller
License
MIT