Skip to content

Support dynamic (catch-all) workflows - #784

Draft
datashaman wants to merge 1 commit into
temporalio:masterfrom
datashaman:feat-dynamic-workflow
Draft

Support dynamic (catch-all) workflows#784
datashaman wants to merge 1 commit into
temporalio:masterfrom
datashaman:feat-dynamic-workflow

Conversation

@datashaman

Copy link
Copy Markdown

Draft — depends on temporalio/sdk-go#2449 (issue temporalio/sdk-go#2448). Not ready to merge until that fix ships and the go.temporal.io/sdk pin here is bumped to include it (see Dependency below).

What

Lets a PHP worker register a dynamic (catch-all) workflow — invoked for any workflow type name that has no statically-registered handler. The host already registers a single shared WorkflowDefinitionFactory proxy (wDef) under each declared name; this adds the ability to register that same proxy via worker.RegisterDynamicWorkflow when the PHP worker declares a workflow as dynamic.

  • internal/worker_info.go — new WorkflowInfo.Dynamic field, populated from the dynamic key the PHP GetWorkerInfo handshake emits.
  • aggregatedpool/workers.go — when a declared workflow is Dynamic, register it via RegisterDynamicWorkflow (reusing wDef, which forwards the real workflow type name to PHP) and skip named registration for it.

Why

Enables Dynamic Workflow support in the PHP SDK — PHP and TypeScript are the only SDKs without it. It lets applications that author workflows at runtime (e.g. UI-driven pipeline/automation builders) give each workflow its own type name — real identity in the Web UI — while a single PHP handler interprets it, with no codegen or per-workflow deploy. Companion PHP change: temporalio/sdk-php (declares the dynamic workflow + emits the dynamic WorkerInfo field).

Dependency — must land first

Requires temporalio/sdk-go#2449 (issue temporalio/sdk-go#2448). RegisterDynamicWorkflow accepts the WorkflowDefinitionFactory wDef, but go-sdk's dynamic execution path currently reflects it as a function and panics (reflect: call of reflect.Value.Call on ptr Value). This repo pins go.temporal.io/sdk v1.44.1, so a bump to the first release containing that fix is needed before dynamic dispatch actually runs at execution time. I'll add that commit once the release is available; until then this compiles and registers, but a dynamic task panics at execution.

Testing

  • go build ./... and go vet ./... clean.
  • End-to-end with a custom rr built from this change + a local go-sdk carrying #2449 + a forked sdk-php: starting an unregistered type (pipeline-blog-publish) is caught by the shared proxy, dispatched to the PHP dynamic handler (which reads the real type via Workflow::getInfo()), and completes → {"dispatchedType":"pipeline-blog-publish"}. Without the go-sdk bump, the same run fails with a WorkflowTaskFailed carrying the reflect panic.
  • Full integration coverage lands with the sdk-php PR (the PHP suite exercises the dynamic path once the dynamic WorkerInfo field is emitted).

Backwards compatibility

Additive. Dynamic defaults to false (omitted from the handshake JSON), so existing workers register exactly as before.

Allow a PHP worker to register a dynamic (catch-all) workflow, invoked for
any workflow type name that has no statically registered handler. The host
already registers a single shared WorkflowDefinitionFactory proxy (wDef)
under each declared name; when a workflow is declared dynamic, register that
same proxy via worker.RegisterDynamicWorkflow instead (it forwards the real
workflow type name to PHP), and skip named registration for it.

WorkflowInfo gains a Dynamic field, populated from the "dynamic" key the PHP
GetWorkerInfo handshake emits.

This enables Dynamic Workflow support in the PHP SDK (PHP and TypeScript are
the only SDKs without it). Companion change: temporalio/sdk-php.

Depends on temporalio/sdk-go#2449 (issue #2448): RegisterDynamicWorkflow
accepts the factory, but go-sdk's dynamic execution path panics on it until
that fix ships. A go.temporal.io/sdk bump to the first release containing it
is required before dynamic dispatch runs.
@datashaman
datashaman force-pushed the feat-dynamic-workflow branch from b6563aa to d24901b Compare July 10, 2026 12:32
datashaman added a commit to datashaman/sdk-php that referenced this pull request Jul 10, 2026
Add `#[WorkflowMethod(dynamic: true)]` to declare a dynamic (catch-all)
workflow — invoked when the worker receives a workflow whose type name is
not statically registered. WorkflowReader flags the prototype; StartWorkflow
falls back to the dynamic prototype when no named workflow matches; and the
GetWorkerInfo handshake advertises `dynamic` so the RoadRunner temporal
plugin can register a Go dynamic-workflow proxy for it.

As in the other SDKs (Go panics, Python raises), at most one dynamic workflow
may be registered per worker — WorkflowCollection enforces this.

Enables Dynamic Workflow support in the PHP SDK (PHP and TypeScript are the
only SDKs without it).

End-to-end dispatch also requires temporalio/roadrunner-temporal#784 (register
the dynamic proxy) and temporalio/sdk-go#2449 (execute a factory-registered
dynamic workflow).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant