Hourglass (hourglass v0.1.0)

Copy Markdown View Source

Hourglass — a standalone Elixir SDK for Temporal (https://temporal.io).

Workflow and activity definitions, a worker that polls a Temporal cluster, a client for starting and awaiting workflows, a deterministic replayer, and a Rust NIF bridge over temporalio-sdk-core.

See Hourglass.Workflow, Hourglass.Activity, Hourglass.Client, and Hourglass.Worker.

Top-level facade

Top-level facade for the Hourglass SDK. start/3, signal/3, cancel/2, status/1,2, history/1, and result/2 are the primary entry points for interacting with a Temporal cluster.

All facade functions accept either a %WorkflowHandle{} or a bare workflow-id string — the string form is normalised to %WorkflowHandle{id: id, run_id: ""} before dispatch.

Backend dispatch

The cluster-facing operations resolve their backend via Hourglass.Client.Backend.impl/0:

  • Production / :integration tests → Hourglass.Client.Real (Bridge NIFs, real cluster).
  • Default-suite tests → Hourglass.Client.Mock (Mox), backed by Hourglass.Test.HourglassCase and friends.

See Hourglass.Client for the lower-level Client helpers and Hourglass.Bridge for the NIF wrappers.

Polling for a workflow result

result/2 polls status/2 until the workflow closes (or the timeout budget expires) and extracts the close result from the workflow history.

Summary

Functions

Requests cancellation of a workflow execution.

Fetches the full event history for a workflow execution.

Polls Hourglass.status/2 until the workflow closes or the budget expires, then extracts and returns the close result.

Sends a signal to a workflow execution.

Starts a new workflow execution.

Synchronous snapshot of a workflow execution's current state.

Functions

cancel(handle_or_id, reason \\ "")

@spec cancel(Hourglass.WorkflowHandle.t() | String.t(), String.t()) ::
  :ok | {:error, Hourglass.Error.t()}

Requests cancellation of a workflow execution.

Accepts a %WorkflowHandle{} or a bare workflow-id string. The reason is optional (defaults to "").

history(handle_or_id)

@spec history(Hourglass.WorkflowHandle.t() | String.t()) ::
  {:ok, Temporal.Api.History.V1.History.t()} | {:error, Hourglass.Error.t()}

Fetches the full event history for a workflow execution.

Accepts a %WorkflowHandle{} or a bare workflow-id string.

result(handle_or_id, opts \\ [])

@spec result(
  Hourglass.WorkflowHandle.t() | String.t(),
  keyword()
) ::
  {:ok, term()}
  | {:error,
     :timeout
     | :failed
     | :canceled
     | :terminated
     | :continued_as_new
     | :timed_out
     | :unknown, Hourglass.WorkflowStatus.t()}
  | {:error, Hourglass.Error.t()}

Polls Hourglass.status/2 until the workflow closes or the budget expires, then extracts and returns the close result.

Accepts a %WorkflowHandle{} or a bare workflow-id string.

Options

  • :timeout — milliseconds (default 30_000). The polling budget.
  • :poll_interval — milliseconds between status polls (default 100).
  • :as — optional type. When provided, casts the raw result via Hourglass.Codec.cast!(type, raw) before returning.

Return

  • {:ok, result} — workflow completed successfully.
  • {:error, :timeout, status} — budget expired before close.
  • {:error, terminal, status} — workflow closed in a non-success terminal state; terminal is one of :failed, :canceled, :terminated, :continued_as_new, :timed_out.
  • {:error, reason} — transport / Bridge error.

signal(handle_or_id, name, payload)

@spec signal(Hourglass.WorkflowHandle.t() | String.t(), String.t(), term()) ::
  :ok | {:error, Hourglass.Error.t()}

Sends a signal to a workflow execution.

Accepts a %WorkflowHandle{} or a bare workflow-id string.

start(workflow_module, input, opts)

@spec start(module(), term(), keyword()) ::
  {:ok, Hourglass.WorkflowHandle.t()}
  | {:error, Hourglass.Error.t()}
  | {:error, Ecto.Changeset.t()}

Starts a new workflow execution.

id is required (passed as id: "some-id" in opts). The input is cast+validated against the workflow module's declared input type before the backend is called. If validation fails the backend is never called and {:error, %Ecto.Changeset{}} is returned.

Options

  • :id (required) — stable workflow ID.
  • :task_queue — defaults to "default".
  • :namespace — defaults to the configured namespace.

status(handle_or_id, opts \\ [])

@spec status(
  Hourglass.WorkflowHandle.t() | String.t(),
  keyword()
) :: {:ok, Hourglass.WorkflowStatus.t()} | {:error, Hourglass.Error.t()}

Synchronous snapshot of a workflow execution's current state.

Wraps DescribeWorkflowExecution (always) and GetWorkflowExecutionHistory (when failures: :include).

Options

  • :failures:exclude (default) | :include. When :include, walks the workflow's history for ActivityTaskFailed events and populates WorkflowStatus.recent_failures. Otherwise recent_failures is nil.

:exclude issues exactly one Bridge call (cheap; suitable for production heartbeat polling). :include issues two Bridge calls (the second walks history; suitable for tests + on-demand operator tooling).