Complete Parent workflow, once ChildWorkflow is scheduled/started

I want my parent workflow to call a long running child workflow asynchronously.
I want to keep it untype (for future flexibility). so here is what I am doing as per docs

        val childUntyped = Workflow.newUntypedChildWorkflowStub(
            workflowType,
            ChildWorkflowOptions.newBuilder()
                .setWorkflowId(workflowId)
                .setTaskQueue(taskQueue)
                .setParentClosePolicy(ParentClosePolicy.PARENT_CLOSE_POLICY_ABANDON)
                .build()
        )
     
        val childExecution = childUntyped.executeAsync(
            Unit.javaClass,
            definition
        )
        // Important:This is to ensure that a Child Workflow Execution starts before the parent closes.
        // If the parent initiates a Child Workflow Execution and then completes immediately after,
        // the Child Workflow will never execute. Refer: https://docs.temporal.io/application-development/features?lang=java#parent-close-policy
        childExecution.get()

        log.info("Successfully Scheduled Child workflow")

both workflows are kicked off.

  • child workflow has a timer and is still running.

  • I expected the parent workflow to complete after the child workflow has started. but I see it is still waiting for the promise - childExecution.get()

I am not sure why the promise is not returned after child has started?

ChildWorkflowStub.executeAsync returns a Promise that becomes ready when a child workflow completes. Use ChildWorkflowStub.getExecution() to get a Promise that becomes ready when the child workflow starts.

@maxim if you are using ChildWorkflowStub.getExecution(), how would you pass a payload to the child workflow? With executeAsync, one of the arguments is args, which is where the WorkflowExecutionStarted data comes from I think, but I’m not seeing a way to do that with getExecution

See this sample: Best way to create an async child workflow - #2 by maxim

Is there an example for newUntypedChildWorkflowStub? That example has the child workflow being typed

Use

child = Workflow.newUntypedChildWorkflowStub(workflowType, childOptions);
Promise<...> result =child.executeAsync(..., args);
child.getExecution().get();

It does not look like that is possible? I can’t seem to call getExecution on the promise

I’m on temporal-sdk:1.21.1

Hi @Zach_Attas

I think it is on the UntypedChildWorkflowStub : childUntyped.getExecution()

Let me know if it works.
Antonio

Thanks @antonio.perez will try that! And now, however, SUPER struggling to unit test this behavior as well, since, the examples for unit testing parent-> child stuff do it with typed workflows…how would one unit test the untyped variety?

Also, I tested UntypedChildWorkflowStub : childUntyped.getExecution()

It did not work, it said that the execution was Initialized, but never created the child workflow

ok let me test this and come back.

Is the issue with the test mocking the child workflow?

Its 2 issues,

  1. How do you properly kick off an UNTYPED child workflow, and get the parent workflow to report when the child workflow STARTED, but not stay open for the whole child execution, aka, have the parent be done when the child is certain that it is entered into temporal and/or started but not stay open. If it stays open, it makes our workflow slower, and its harder to measure the speed of each individual workflow. We don’t need the parent to stay open while the child executes
  2. How do you unit test said behavior? When I wrote tests without doing this, they just hang. But I’m not sure also how to implement that example, with an UNTYPED child workflow

@Zach_Attas

I have written an example with the implementation

and the test

Let me know if it helps,

Antonio

My issue with the unit test example is here https://github.com/antmendoza/temporal_samples-java/blob/b19255791701db48af7eed3c18d06d7557700163/core/src/test/java/io/temporal/samples/asyncuntypedchild/AsyncUntypedChildTest.java#L49C5-L58C16

I don’t have the child workflow defined in this repo, its another repo, which is why im using the untyped strategy

@Zach_Attas

I guess then the child is running in a different taskqueue?

If you don’t need to test if the child is running, just remove registerWorkflowImplementationFactory and the asserts related to the child workflow from test code.

If you need to test the child is running after the parent has completed,

  • I think you still need an interface:
    //worker listening in the child taskqueue
    Worker workerChildTaskqueue =
        testWorkflowRule.getTestEnvironment().newWorker("child-taskqueue");

    // Factory is called to create a new workflow object on each workflow task.
    workerChildTaskqueue.registerWorkflowImplementationFactory(
        ChildWorkflow.class,
        () -> {
          ChildWorkflow child = mock(ChildWorkflow.class);
          return child;
        });


  Note that the taskqueue for the worker running the child workflow in your case will be different (not "child-taskqueue")
  • or you can get the workflow history of the parent workflow and look for the eventType = ChildWorkflowExecutionStarted
    assertTrue(
        testWorkflowRule
            .getTestEnvironment()
            .getWorkflowExecutionHistory(execution)
            .getHistory()
            .getEventsList()
            .stream()
            .anyMatch(f -> f.hasChildWorkflowExecutionStartedEventAttributes()));

Let me know how it goes,
Antonio