Triggering Synchronous and Asynchronous Workflows from a workflow

Child workflow start is asynchronous. You have to wait for the child to start before signaling it. See this post that explains on how to wait for the child to start.

I have tried this approach, however, it doesnā€™t look like the @WorkflowMethod of the child workflow is getting triggered. This is what the stripped down code of the child workflow looks like:

@WorkflowInterface
public interface ChildWorkflow {
	@WorkflowMethod
	public void register();
}

public class TestChildWorkflow implements ChildWorkflow {
	@Override
	public void register() {
		System.out.println("TestIngestWorkflow.register START");
		
		Workflow.sleep(5000);
		
		System.out.println("TestIngestWorkflow.register STOP");
	}
}

and in the parent job queue workflow the addTaskTest() is a @SignalMethod. This is how it is being triggered

	public void addTaskTest() {
		// Note: the parent close policy must be set in order for the child workflows to be run asynchronously
		// and continue to run after the parent workflow has completed
		ChildWorkflowOptions options = ChildWorkflowOptions.newBuilder()
				.setParentClosePolicy(ParentClosePolicy.PARENT_CLOSE_POLICY_ABANDON)
				.build();
		
		ChildWorkflow w = Workflow.newChildWorkflowStub(ChildWorkflow.class, options);
		
		System.out.println(String.format("addTask() call register start"));
		Async.procedure(w::register);
		System.out.println(String.format("addTask() call register stop"));
		
		// Wait for child to initialise
		System.out.println(String.format("addTask() getExecution start"));
		Promise<WorkflowExecution> childExecution = Workflow.getWorkflowExecution(w);
		childExecution.get();
		System.out.println(String.format("addTask() getExecution stop"));
	}

when I run this I see the output:

addTask() call register start
addTask() call register stop
addTask() getExecution start

I do not see the output in the child workflow register() method to indicate itā€™s being called. Also it never prints out after the childExecution to indicate that the child has started.

Donā€™t use System.out.println in your workflow code, use Workflow.getLogger(ā€¦).info(ā€¦) instead.

Since you are using PARENT_CLOSE_POLICY_ABANDON
your call to childExecution.get() is going to block until the child workflow starts execution (or the start fails), and not until the child workflow finishes its execution. So in your addTask method you are just starting child workflow execution, not waiting for it to complete.

Have you checked in the web ui to see if your child workflow was executed? Or you can check its status as shown in this example: samples-java/src/main/java/io/temporal/samples/asyncchild at master Ā· temporalio/samples-java Ā·

OK, I swapped over to use the Workflow.getLogger(ā€¦)

In the actual implementation what actually happens is

  1. The register() method is called to start the child workflow. The register method does some very basic external logging via an activity to register that it is running and then blocks. The code looks like this:
	public void register() {
		performRegister();
		
		// wait until the start processing signal
		if(!startProcessingTrigger) {
			Workflow.await(() ->  startProcessingTrigger);
		}

		// continue processing
		// ...
	}

	// this is a signal method
	public void startProcessing() {
		startProcessingTrigger = true;
	}

  1. Once the register method is called the child workflow is then added to the queue in the parent workflow so they can be processed sequentially. This means that all the child workflows in the queue should already be running but be blocking.
  2. When a child workflow is taken off the queue the parent workflow sends a signal to the child workflow to continue processing via the startProcessing() method

So all I want to do is start the child workflows - I donā€™t want to wait for them to finish. From the logging what am I seeing is that the async call Async.procedure(w::register) has not completed starting the child workflow execution before the Job Queue workflow method execute() is called so the parent workflow exits out

This is how a task gets added to the queue where the parent workflow is the JobQueueWorkflow

JobQueueWorkflow workflow = workflowClient.newWorkflowStub(JobQueueWorkflow.class, options);
BatchRequest request = workflowClient.newSignalWithStartRequest();
request.add(workflow::execute);
request.add(workflow::addTaskTest);
workflowClient.signalWithStart(request);

The execute() method is the @WorkflowMethod of the JobQueueWorkflow and the addTaskTest() is a @SignalMethod. When calling the signalWithStart(request) does the execute() get called before the addTaskTest(). Iā€™m not clear on exactly how this works but it looks like because the addTaskTest blocks until the child workflow has started the execute() method has been called and exits out because there are no tasks to be processed on the queue.

Are you able to explain in more details the sequence of steps that would be run when the batch request is called?

If this workflow is already running, only the signal is sent.
If its not running, its started, and then signalled.
You can test it out in this sample as well.

Start from looking at the workflow execution history for both parent and the child. It should say exactly what happened.

I think the problem was a ā€˜race-conditionā€™ between calling execute() to start the parent workflow and then calling the signal method addTaskTest(). Because I waited in the addTaskTest() for the child workflow to start. the execute() method finished running before the addTaskTest() had a chance to add the task to the queue.

To fix the issue I added a wait in the execute() until the task has been added to the queue.

To let the parent know when the child has completed I implemented @maximā€™s suggestion to send a signal back to the parent from the child when it completes. This is working as expected.

Question: once I have looked up the child workflow is there a way to get back a Promise that you can then wait on for the child to finish (as an alternative to having the child send back a signal to the parent)?

Question: once I have looked up the child workflow is there a way to get back a Promise that you can then wait on for the child to finish (as an alternative to having the child send back a signal to the parent)?

You cannot until this feature request is implemented.