Call query method of a child workflow from the query method of parent

I have a long-running workflow “Workflow1” from which I start a child workflow “Workflow2” (which is also a long-running workflow) in async.
I store the workflowId of the child workflow in the state of the parent workflow while starting the child workflow in async as shown below

ChildWorkflowStub childWorkflowStub =
        Workflow.newUntypedChildWorkflowStub(value.workflowName, kycWorkflowOptions);

childWorkflowStub.executeAsync(Void.class);
Promise<WorkflowExecution> childWorkflowExecution = childWorkflowStub.getExecution();

childWorkflowId = childWorkflowExecution.get().getWorkflowId()

I only want to expose the Parent workflow to the services.
To achieve this, we have exposed signal and query methods from the parent workflow, from which I need to call the child workflow’s signal/query method respectively.

I am able to call the signal method of child workflow from the signal method in parent workflow.

But not able to figure out a way to trigger the query method of a child workflow from the query method of the parent. Is this possible?

Hello @Aliasgar

But not able to figure out a way to trigger the query method of a child workflow from the query method of the parent. Is this possible?

It is not possible. One thing you can do is to signal the parent workflow from the child workflow when the childWorkflow state change.

I only want to expose the Parent workflow to the services.

You can dynamically add signal and query handlers to your workflows so they are not included in the workflow interface, for example:

Workflow.registerListener(
    (DynamicSignalHandler)
        (signalName, encodedArgs) -> {
      // ...
});

 Workflow.registerListener(
    (DynamicQueryHandler)
        (queryType, encodedArgs) -> {
          // ...
});

Note that if you have a concrete signal method handler define in your workflow interface it would be called for the associated signal, if not the dynamic one would.

But not able to figure out a way to trigger the query method of a child workflow from the query method of the parent. Is this possible?

Signal methods are executed inside workflow thread so in signal handler you could use ExternalWorkflowStub to signal the child if you wanted (which has the dynamic signal handler defined). This is not possible with query handlers however.

One thing you could consider is utilizing workflow id for parent/child so for example child workflow id could based on parent workflow id plus some known postfix so from the client perspective you would be able to signal/query child by just knowing the parent workflow id.

1 Like

Thanks @tihomir for the elaborate response

This is exactly how I have implemented it.

Is there any possibility of this being picked up for development at some point?
It would make the code in consuming services much more clean and elegant if there is a capability to Call Query Methods of external/child workflows from Query method of a Workflow. :slight_smile:

Do agree that having to use activity to query external workflow from another workflow is not the most user friendly approach. Opened issue here, hope it helps.

2 Likes

That issue was closed because its not an SDK issue but requires new server support. Does anyone have a link to a tracking issue for server support for this?

Parent workflows are also unable to call update on their children, for example to wait for and obtain responses.

It is quite an annoying limitation to have to run the update in an activity.

100% agree. We are aware of this limitation and will add support for cross-workflow updates and queries. As usual, we have to balance this specific feature against all the other priorities, so ETA is not clear.

1 Like

Another complexity of calling child workflow methods in activities is dealing with timeouts.

I have an @Update method in the child workflow that waits for an await. Normally this will happen quickly but if the child workflow fails for some reason, then it could take a long time while code is updated and deployed.

The parent workflow activity that calls this @Update keeps timing out and restarting the @Update – but the previous @Update does not get cancelled and remains running. After some time we start getting the error in the parent:

"RESOURCE_EXHAUSTED: limit on number of concurrent in-flight updates has been reached (10)

Thinking through ways to solve this… one approach is to await with a timeout. If the child workflow times out, the parent activity heartbeats and retries. Is there a better approach? Maybe a way to ensure the previous update is cancelled on timeout?

The best workaround is to avoid using updates from workflow to workflow. Instead, use signals for both request and reply.

The best workaround is to avoid using updates from workflow to workflow. Instead, use signals for both request and reply.

Hmm, interesting. But the downside of this is that the child workflow now has to be “aware” of its parent, which couples them together to some extent. I can use a dynamically typed stub for the parent, but the parent needs to have a pre-agreed signal mechanism available.

Also async signals make other logic more complex – for example, if the parent launches multiple children in parallel, the signaling mechanism now needs correlation logic as well.

Its not a show-stopper, but is there a way to avoid or reduce the impact of the coupling? I guess one approach could be to pass in the name of the parent’s signal method as an input or signal to the child.

Is it allowed for the child’s signal handler to await and then trigger a signal to the parent?

I agree that direct support of Update is superior to the workaround. It is ok to await in the signal handler.

1 Like