Skip to content

[bundle] #[AsWorkflow] is not autoconfigured: WorkflowPass finds nothing unless the class is tagged by hand #255

Description

@gabiudrescu

What happens

A workflow class carrying #[AsWorkflow] in a Symfony application is never registered. WorkflowRegistry stays empty for it, and starting an execution fails with:

Unknown workflow type: OrderFulfilment

Why

DurableBundle::build() registers attribute autoconfiguration for three attributes:

  • AsActivityHandler → tag durable.activity_handler
  • AsNexusServiceHandler → tag NexusHandlerPass::TAG
  • FulfilsNexusOperation → tag NexusHandlerPass::FULFILMENT_TAG

AsWorkflow is not among them. WorkflowPass then iterates findTaggedServiceIds('durable.workflow'), and no compiler pass and no configuration ever applies that tag. A grep across durable-bundle finds 'durable.workflow' in exactly one place: the pass that reads it.

The documentation says the opposite - the host table in the workflow reference reads "Symfony, Sylius | autoconfigured from the attribute", and contrasts it with Laravel and Magento where the class must be named explicitly.

Reproduce

Sylius 2.2.1 / Symfony 7.4.2 / PHP 8.3, gplanchat/durable-bundle v0.1.0-alpha10.

#[AsWorkflow('OrderFulfilment')]
final class OrderFulfilmentWorkflow
{
    public function __construct(private readonly WorkflowEnvironment $environment) {}

    #[AsWorkflowMethod]
    public function run(string $orderNumber): string { /* … */ }
}

bin/console debug:container --tag=durable.workflow lists nothing.

Suggested fix

Add the fourth registration in DurableBundle::build():

$container->registerAttributeForAutoconfiguration(
    AsWorkflow::class,
    static function (ChildDefinition $definition): void {
        $definition->addTag('durable.workflow');
    },
);

One wrinkle worth deciding at the same time: a workflow is instantiated by WorkflowDefinitionLoader::instantiate() through reflection, not by the container, and its constructor takes a WorkflowEnvironment that is not a service. So autoconfiguring the tag also needs the service definition to skip autowiring, otherwise the container fails to compile on a class it will never build. Marking such definitions autowire: false inside the autoconfiguration callback would make the attribute work on its own.

Workaround in use

App\:
    resource: '../src/'
    exclude:
        - '../src/Workflow/'

App\Workflow\OrderFulfilmentWorkflow:
    autowire: false
    autoconfigure: false
    tags: ['durable.workflow']

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    loop:clearedA human has read this issue and cleared it for the loop

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions