What a namespace is
A namespace is a routing value that the engine stores with a function id and a worker name. It is not part of either value. For examplestate::get can exist as the same function id in default,
orders, and analytics namespaces.
The engine uses these registry keys:
(namespace, function_id)for functions.(namespace, worker_name)for workers.(namespace, trigger_type_id)for trigger type providers.
Trigger types and the two namespaces a trigger names
A trigger names two namespaces, and they answer different questions:namespaceis where the target function resolves when the trigger fires.trigger_namespaceis where the trigger type’s provider is found.
namespace absent means the engine’s default namespace.
trigger_namespace absent is not default: the engine resolves it, taking the
registering worker’s namespace first and the default namespace second.
That order is what lets a project ship its own provider for a trigger type the
engine also provides. The engine’s own providers (http, cron, state,
stream) live in the default namespace, so a worker that names nothing reaches
them. A project that registers its own provider for the same type id gets that
one instead, without any worker changing how it binds.
Naming trigger_namespace explicitly is strict: that namespace or nothing. A
binding that names one is never moved.
A provider that registers after a binding already fell back to the default
namespace claims that binding back. Start order therefore does not decide which
provider serves a project.
What namespaces enable
Namespaces let you ship one reusable worker package and deploy it for more than one tenant on the same engine. Each tenant can run a worker namedstate and expose state::get. The worker package
does not need tenant-specific names.
Why the namespace is not a prefix
iii does not changestate::get to orders/state::get. A function id is part of the worker
contract. It appears in schemas, skills, console output, commands, and documentation. A deployment
value must not change that contract.
The worker author defines the function id. The operator selects the namespace when they deploy the
worker. These two values stay separate.
Why routing is strict
A call withnamespace: "orders" resolves in orders only. A call with no namespace resolves in the
namespace of the calling worker.
The engine does not search other namespaces after a miss. A fallback could send a call to another
tenant. Instead, the engine returns function_not_found and lists the namespaces where the function
id exists.
The discovery functions are less strict when no namespace is present. For engine::functions::info
and engine::workers::info, a default entry has priority. If there is no default entry, a name
that exists in only one namespace resolves there. A name that exists in multiple namespaces returns
an ambiguity. An explicit namespace always uses strict resolution.
Why the engine rejects a collision
Only one live worker can own a worker name in a namespace. Only one live worker can own a function id in a namespace. The engine rejects a second owner instead of replacing the current owner. A worker-name conflict is fatal. The engine closes the new connection because the worker cannot use its declared identity. A function-id conflict rejects only that function. The worker stays connected and serves its other functions. Worker registration and function registration are separate operations. A connected worker does not confirm that all its functions are registered. The SDK reports a function conflict as a warning. A restart does not conflict with its own connection after teardown starts. The new connection can reclaim the same worker name.How a connection gets its namespace
A worker declares its namespace in theengine::workers::register call. The engine starts a
namespace timer when the WebSocket connection opens. The default timeout is 5000 ms.
A client can send registration messages before engine::workers::register. The engine holds
RegisterFunction, UnregisterFunction, RegisterService, RegisterTrigger, and
UnregisterTrigger messages until it knows the namespace. It does not register them in default
and move them later.
If engine::workers::register arrives first, the engine sets the declared namespace. An absent
value selects default. The engine then processes the held messages in arrival order.
If the timer expires first, the engine sets the connection namespace to default and processes the
held messages. A later worker registration cannot change that namespace.
To change the timeout, use registration_namespace_grace_ms or III_NAMESPACE_GRACE_MS. See
Registration namespace timeout.