Skip to main content
0.23.x adds namespaces as a routing dimension. Workers that declare no namespace land in default and behave exactly as before, so most projects upgrade with no code change. The one hard break is durable queue naming on the RabbitMQ adapter. Apply the steps below that touch surfaces your project uses.

Step 1: Redeclare RabbitMQ durable subscriber queues

Durable subscriber queue names are now namespace-qualified, so two subscribers of the same topic and function id in different namespaces get two queues instead of competing for one. After the upgrade, a 0.23 subscriber declares and consumes a new namespace-qualified queue. The RabbitMQ adapter does not rename, consume, or migrate the old queue. The old queue and its durable binding remain in RabbitMQ until you delete the queue. Messages in it remain unread, and the binding can continue to route copies of new events to it. {ns} is the subscriber’s namespace, default when it declared none. Any @ or \ inside a topic, function id, or namespace is backslash-escaped before the join.
Drain the old queues before upgrading. Messages left in a pre-0.23 queue are not migrated and no consumer will read them afterwards.
For each affected subscriber:
  1. Stop publishing to the topic.
  2. Let the existing consumers drain the old queue to empty.
  3. Upgrade and restart. The adapter declares the new namespace-qualified queue on the next subscribe.
  4. Delete the drained queue and its dead-letter queue from the broker.

Step 2: Verify migration of engine-managed queues

This step applies when your deployment stores durable queues in the queue storage managed by the engine. It does not apply to RabbitMQ. At startup, before queue consumers start, the engine scans the stored durable subscriber queues. For each queue without a namespace, it moves the waiting, active, delayed, and dead-letter entries to the same queue in default. Active jobs return to the waiting state. Delayed jobs keep their scheduled time. The engine uses default because a legacy queue does not contain a namespace. The migration is idempotent. If startup stops during migration, the next startup continues without duplicating jobs. The engine logs each migrated queue:
If a legacy queue name contains @, the engine cannot determine if the character is part of the old name or marks a namespace. It does not migrate that queue and logs this warning:
If you see this warning, stop publishing. Restart 0.22.x with the same queue storage, let its consumer drain the skipped queue, and then repeat the upgrade.

Step 3: Tune the registration grace period, if needed

A connection gets its namespace from engine::workers::register. A client can send registration messages before this call. The engine holds these messages until the namespace is known, or until the grace period expires and the connection is set to default. The default grace period is 5000 ms. Raise it if workers on slow links register but land in default unexpectedly:
config.yaml
Set III_NAMESPACE_GRACE_MS in the engine process environment, not in a worker environment. It applies to namespace resolution for all new worker connections and overrides registration_namespace_grace_ms.

Step 4: Check for engine::* function ids outside default

Most custom workers do not use the engine:: prefix. Check this step because the new rule rejects an existing custom function that uses the prefix outside default.
Every worker has a namespace. A worker uses default if you do not specify a namespace. engine::* is reserved for engine infrastructure, which is registered in default. If a worker in a non-default namespace registers an engine::* function id, the engine rejects that registration with FUNCTION_NAMESPACE_CONFLICT. The connection stays open, and its other functions continue to serve requests. Rename the function with your own service::name prefix. The queue worker supplied with the engine registers its engine::queue::* functions in default. The rule does not reject these functions. It applies to a custom worker connection that registers an engine::* function in a non-default namespace.

Step 5: Scope RBAC rules when adopting a namespace

Two RBAC surfaces changed, and both matter only for a worker that leaves default. First, expose_functions rules on the iii-worker-manager RBAC listener are namespace-scoped. A rule that names no namespace applies to default only, so it will not expose a function reached in another namespace. When you move a worker into a namespace, scope its rules to match:
Add one rule for each namespace the session reaches. See Namespace-scoped function rules for the matching syntax. Second, allowed_functions on the auth result now applies in default only. It used to apply in every namespace, so a grant issued for one tenant answered for every other tenant exposing the same function id. If your auth function returns allowed_functions for a worker that runs in a namespace, move those grants into namespaces, which the auth result now carries. See Scope a session to namespaces. forbidden_functions is unchanged and still applies in every namespace. An auth function that returns no namespaces keeps the behaviour it had.

Migration checklist

  • Drain and delete pre-0.23 RabbitMQ subscriber and dead-letter queues (Step 1)
  • Confirm the engine logged each legacy queue migration on startup (Step 2)
  • Recover each queue that the legacy migration skipped because its name contains @ (Step 2)
  • Raise registration_namespace_grace_ms if workers land in default unexpectedly (Step 3)
  • Rename engine::* function ids registered by namespaced workers (Step 4)
  • Add namespace: to expose_functions rules for namespaced workers (Step 5)
  • Move allowed_functions grants for namespaced workers into namespaces (Step 5)

Result

The project runs on 0.23.x with durable subscriptions consuming from namespace-qualified queues. Workers that declare no namespace keep routing through default exactly as they did on 0.22.x, and workers that declare one own their function ids inside it.
To configure workers and calls, see Use namespaces. To understand strict routing, see Namespaces.