You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Add stable logical aliases for immutable concrete flow versions through a DeployedFlow wrapper.
Callers start a stable alias such as greetUser. Startup deployment resolves that alias to one concrete version such as greetUserV2. Runs, tasks, queues, broadcasts, and history retain the concrete slug.
Alias metadata remains independent from DAG shape and queue mode.
A plain Flow remains supported and defaults to a self-alias:
alias = concrete flow_slug
defineDeployedFlow() preserves the exact wrapped plain or step-queued flow type. It must not weaken handler, dependency, condition, queue-mode, step-selector, context, or environment inference.
Ownership model
flow_slug
immutable concrete version and runtime identity
flow_alias
stable dispatch name with one active concrete target
Flow or StepQueuedFlow
DAG, handlers, and queue mode
DeployedFlow
immutable alias membership for one concrete definition
Aliases never appear in generated private queue names. Queue names use the concrete slug so versions remain isolated.
Data model
Add immutable alias membership and one active pointer:
pgflow.flows
flow_slug primary key
flow_alias not null
unique (flow_slug, flow_alias)
pgflow.flow_aliases
flow_alias primary key
flow_slug not null
created_at timestamptz not null
updated_at timestamptz not null
foreign key (flow_slug, flow_alias)
references pgflow.flows (flow_slug, flow_alias)
Invariants:
every concrete flow has one immutable alias membership;
omitted aliases resolve to the concrete slug;
several concrete versions may share one alias;
exactly one concrete version is active for each alias;
an existing concrete slug cannot move to another alias;
existing flows backfill as self-aliases;
the migration does not infer version families from slug suffixes.
Startup deployment and activation
Every worker carries the complete wrapped definition. Use one lock order everywhere:
compile or verify the complete concrete flow shape, queue mode, and route map;
set the active pointer only when the alias has no active version yet;
commit before worker registration.
Compiling a new concrete version for an existing alias never changes the active pointer. This prevents concurrent V2 and V3 deployments from using last-lock-holder-wins activation.
Activation rules:
the first concrete member initializes an empty alias;
later concrete versions remain inactive after compilation;
rechecking the active slug preserves activation;
rechecking an inactive slug leaves it inactive;
restarting an old worker never reclaims the alias;
local destructive recompilation preserves membership and activation state;
alias mismatch always fails;
worker startup failure cannot switch an existing alias.
Several step workers may race to deploy the same concrete version. The locks make one compile and the others verify.
Start APIs
Move concrete behavior behind explicit slug functions and make aliases the default:
start_flow() alias
start_flow_by_alias() alias, explicit
start_flow_by_slug() concrete slug
start_flow_with_states() alias
start_flow_with_states_by_slug() concrete slug
Compatibility:
keep the existing flow_slug RPC argument name on default start functions;
missing aliases fail and never fall back to concrete lookup;
alias resolution and concrete start happen in one database call;
returned runs and events expose the resolved concrete slug.
Clients use alias semantics by default and add startFlowBySlug() for pinned starts.
Activation, rollback, and deletion
Add one compare-and-swap operation:
pgflow.activate_flow_version(
flow_alias text,
flow_slug text,
expected_current_flow_slug text
)
It validates membership, takes the alias lock, compares the current pointer, and atomically switches only when the expected current version still matches. The caller uses null only to initialize an alias with no active version.
Production rollout follows #654: deploy and enable the complete new worker set, verify every target queue has coverage, then call activate_flow_version(). Rollback uses the same expected-current check.
Keep deletion concrete-slug based. Rules:
deleting an inactive version is allowed;
deleting the active target is blocked by default;
removing an alias requires that concrete slug to be its sole version;
future explicit shared queues are never dropped with one version.
Recompilation and membership
Alias membership and the active pointer must survive fenced local recompilation.
Once aliases exist, destructive recompilation replaces only the concrete definition's runtime rows, steps, route metadata, and private queues. It must not delete and recreate the identity row referenced by alias membership.
Take alias and concrete locks in the documented order for activation, recompilation, and alias-aware deletion.
Versioned private queues
For a step-queued deployment:
greetUserV1 -> V1 private step queues
greetUserV2 -> V2 private step queues
alias greetUser -> active concrete version for new runs
Existing V1 tasks never move to V2 queues. Keep V1 workers until no V1 run can create or execute more tasks.
Observability
Startup results and logs distinguish:
compilation: compiled | verified | recompiled
activation: activated | active | inactive
alias
active concrete slug
queue mode
selected worker queue
Do not log credentials or message bodies.
Acceptance criteria
defineDeployedFlow() preserves exact plain and step-queued flow types.
Plain flows retain self-alias behavior.
Every concrete flow has immutable, non-null alias membership.
Existing definitions backfill as self-aliases without suffix inference.
Exactly one active concrete target exists per alias.
New concrete definitions compile completely but do not replace an existing alias automatically.
The first concrete member initializes only an empty alias.
Summary
Add stable logical aliases for immutable concrete flow versions through a
DeployedFlowwrapper.Callers start a stable alias such as
greetUser. Startup deployment resolves that alias to one concrete version such asgreetUserV2. Runs, tasks, queues, broadcasts, and history retain the concrete slug.Alias metadata remains independent from DAG shape and queue mode.
Dependencies and stage
Public API
Plain flow:
Private per-step flow:
A plain
Flowremains supported and defaults to a self-alias:defineDeployedFlow()preserves the exact wrapped plain or step-queued flow type. It must not weaken handler, dependency, condition, queue-mode, step-selector, context, or environment inference.Ownership model
Aliases never appear in generated private queue names. Queue names use the concrete slug so versions remain isolated.
Data model
Add immutable alias membership and one active pointer:
Invariants:
Startup deployment and activation
Every worker carries the complete wrapped definition. Use one lock order everywhere:
Within one startup transaction:
Compiling a new concrete version for an existing alias never changes the active pointer. This prevents concurrent V2 and V3 deployments from using last-lock-holder-wins activation.
Activation rules:
Several step workers may race to deploy the same concrete version. The locks make one compile and the others verify.
Start APIs
Move concrete behavior behind explicit slug functions and make aliases the default:
Compatibility:
flow_slugRPC argument name on default start functions;Clients use alias semantics by default and add
startFlowBySlug()for pinned starts.Activation, rollback, and deletion
Add one compare-and-swap operation:
It validates membership, takes the alias lock, compares the current pointer, and atomically switches only when the expected current version still matches. The caller uses
nullonly to initialize an alias with no active version.Production rollout follows #654: deploy and enable the complete new worker set, verify every target queue has coverage, then call
activate_flow_version(). Rollback uses the same expected-current check.Keep deletion concrete-slug based. Rules:
Recompilation and membership
Alias membership and the active pointer must survive fenced local recompilation.
Once aliases exist, destructive recompilation replaces only the concrete definition's runtime rows, steps, route metadata, and private queues. It must not delete and recreate the identity row referenced by alias membership.
Take alias and concrete locks in the documented order for activation, recompilation, and alias-aware deletion.
Versioned private queues
For a step-queued deployment:
Existing V1 tasks never move to V2 queues. Keep V1 workers until no V1 run can create or execute more tasks.
Observability
Startup results and logs distinguish:
Do not log credentials or message bodies.
Acceptance criteria
defineDeployedFlow()preserves exact plain and step-queued flow types.activate_flow_version()uses expected-current compare-and-swap semantics.Out of scope