Current section
Files
Jump to
Current section
Files
guides/namespaces.md
# Namespaces
Namespaces are soft tenancy inside one Continuum instance and one repo. They are
row metadata on `continuum_runs`, not a separate process tree.
```elixir
{:ok, run_id} =
Continuum.start(MyApp.OrderFlow, input,
namespace: "tenant-a",
attributes: %{region: "eu"}
)
```
`Continuum.list_runs/1` and `Continuum.Observer.list_runs/1` default to the
`"default"` namespace. Pass `namespace: "tenant-a"` to list or search another
namespace.
Run-id keyed operations remain global when `:namespace` is omitted because run
ids are UUIDs. Service layers can add an expected-value guard to every access:
```elixir
Continuum.get_run(run_id, namespace: "tenant-a")
Continuum.await(run_id, 5_000, namespace: "tenant-a")
Continuum.signal(run_id, :approved, %{}, namespace: "tenant-a")
Continuum.cancel(run_id, namespace: "tenant-a")
Continuum.set_attributes(run_id, %{region: "eu"}, namespace: "tenant-a")
```
Every guarded operation returns `{:error, :not_found}` when the run does not
exist or its namespace differs, without revealing which case occurred and
without mutating the run. Signal, cancel, and await retain their existing
behavior of following `continue_as_new` to the live tip.
The host application still owns authentication and authorization; the guard
prevents an already-authorized service path from accidentally crossing tenant
boundaries. For hard isolation, use separate Continuum instances and repos;
namespaces are a softer filter inside one instance.