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

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions