Skip to content

Allow to add custom TaskOrchestrationFactory and TaskActivityFactory factories #1629

Description

@mathecruz

Context

The current API does not allow a custom TaskOrchestrationFactory and TaskActivityFactory, when creating a DurableTaskGrpcWorker through:

  public DurableTaskGrpcWorker build() {
    return new DurableTaskGrpcWorker(this);
  }

Proposal

It would be great, if we have a way to add custom factories to load WorkflowActivity or Workflow implementations through other mechanism, like CDI, by example.

Possible implementation

To change the WorkflowRuntimeBuilder builder adding a new method that adds a custom factories.

For example:

  public <T extends WorkflowActivity> WorkflowRuntimeBuilder registerTaskActivityFactory(String activityName, TaskActivityFactory taskActivityFactory) {
    return null;
  }

  public <T extends Workflow> WorkflowRuntimeBuilder registerTaskOrchestrationFactory(String orchestrationName, TaskOrchestrationFactory taskOrchestrationFactory) {
    return null;
  }

Activity

  1. mathecruz commented on Jan 29, 2026

    @mathecruz
    ContributorAuthor

    /assign

  2. salaboy commented on Jan 29, 2026

    @salaboy
    Contributor

    This kinda makes sense in a way, but here is how we do it in Spring -> https://github.com/dapr/java-sdk/blob/master/dapr-spring/dapr-spring-workflows/src/main/java/io/dapr/spring/workflows/config/DaprWorkflowsConfiguration.java#L51C7-L51C46

    Notice that we as Spring DI to get the beans by type (Beans that implements the Workflow and WorkflowActivity interfaces) and then we register those beans in the workflow runtime. What this does, is instantiate the beans so if they are doing any injection inside this is already resolved by Spring. We didn't needed any new factories or way to register new factories.

    So my question would be, instead of registering the factories that are CDI enabled, why not registering CDI beans to the runtime? (as these beans should already have all their dependencies injected).

    Does this makes sense?
    I trust your Quarkus experience, so if you think registering the factories is the way to go, I am happy to accept these changes, but I wanted to check with you about how do we do it in Spring first.

  3. added this to the v1.17 milestone on Jan 29, 2026
  4. javier-aliaga commented on Jan 29, 2026

    @javier-aliaga
    Contributor

    ey @mcruzdev not sure what you mean with

    The current API does not allow a custom TaskOrchestrationFactory and TaskActivityFactory, when creating a DurableTaskGrpcWorker through:
    
      public DurableTaskGrpcWorker build() {
        return new DurableTaskGrpcWorker(this);
      }
    
    

    The DurableTaskGrpcWorkerBuilder already contains this methods

    public DurableTaskGrpcWorkerBuilder addOrchestration(TaskOrchestrationFactory factory)

    and

    public DurableTaskGrpcWorkerBuilder addActivity(TaskActivityFactory factory)

    as @salaboy says, we may be missing something

  5. mathecruz commented on Jan 29, 2026

    @mathecruz
    ContributorAuthor

    It is a better approach for Quarkus Dapr extension. Dapr works a bit different like Spring. I can solve this problem with a similar approach that @salaboy mentioned, but the user experience on Quarkus side will be affected. I will share with you three approaches that I tried to implement Dapr Workflow in a Quarkus extension.

    Note: I need to create a synthetic bean to do it.

    1. The first one was a similar way that Spring does, getting the beans at RUNTIME and registering workflows and activities as instance.

    The problem: When the user wants to inject a Microprofile RestClient @RestClient in a WorkflowActivity the application do not build, due to a Quarkus particularity, a synthetic bean initialized during RUNTIME_INIT must not be accessed during STATIC_INIT. REST Clients are initialized at STATIC_INIT.

    1. Recording the registration of workflows and activities at STATIC_INIT through a bean listener.

    The problem: It works nicely, but the user experience is impacted:

    With this approach, the user needs to inject the REST Clients in a lazy way: @RestClient @Inject Instace<UserClient> userClient;, it is necessary due the boot proceduce, at which time the REST Client can't be created.

    1. Recording the registration of workflows and activities at STATIC_INIT using a TaskOrchestrationFactory and TaskActivityFactory in a lazy load way. It is a runtime lazy, but depends of this pull request to be merged.
  6. mathecruz commented on Jan 29, 2026

    @mathecruz
    ContributorAuthor

    @javier-aliaga I agree with you. However, the WorkflowRuntimeBuilder does not support this out of the box. I need to create everything manually (DurableTaskGrpcWorker, WorkflowRuntime).

  7. javier-aliaga commented on Jan 29, 2026

    @javier-aliaga
    Contributor

    Gotcha, but I would recommend you to wait to this implementation, I am working in the versioning and it is quite possible things change to support it

  8. mathecruz commented on Jan 29, 2026

    @mathecruz
    ContributorAuthor

    I added a pull request to add it #1630. I am not sure if you would like to reuse or if makes sense to merge as well.

  9. salaboy commented on Jan 29, 2026

    @salaboy
    Contributor

    We need to get this asap, to unblock other initiatives . @javier-aliaga we need to find an alternative that works until we can merge with your approach

  10. javier-aliaga commented on Jan 29, 2026

    @javier-aliaga
    Contributor

    @mcruzdev Can you increase the code coverage? @salaboy We can merge it and I will get into the versionig PR

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

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions