Wait for signal best practices

I am trying to create a workflow that can be described as follows:

  1. Download some file in the local filesystem.
  2. Upload the local file to some other system in order to process it.
  3. Wait for a callback to signal the processing is done with the results, not dependent on any host.
  4. Save the results and trigger some more operations.

I am implementing it using a “local” queue, using the “host dependent queue” pattern from the FileProcessingWorkflow example to make the steps 1 and 2 run on the same host.

In order to wait for the completion signal, I am using the following pattern:

        while (true) {
            Workflow.sleep(LOOP_TIMEOUT);
            if (!Objects.isNull(result)) {
                log.info("result received!");
                break;
            } else {
                log.info("Still waiting...");
            }
        }

where the signal method just assigns the result field of the workflow class.

I am not sure at all the approach is sound, especially in regards to the sleep loop. I am wondering if it would make more sense in regards to temporal best practices to split my workflow in two, one to download and submit the file for processing and once I get my callback, to trigger a second workflow with the processing result as input.

Second question, more for my understanding of temporal: I started by implementing the wait section described above as:

        while (true) {
            if (!Workflow.await(LOOP_TIMEOUT, () -> !Objects.isNull(result))) {
                break;
            }
        }

But then my test was failing with a “possible deadlock detected: workflow thread did not yield control within 1s”. Why is that ?
I was sending the signal using a mock of my activity using the following code:

        willAnswer((Answer<Void>) invocation -> {
            testEnv.registerDelayedCallback(Duration.ofSeconds(2), () -> {
                workflowById.completeProcessing(result);
            });
            return null;
        }).given(hostSpecificActivity).submitForProcessing(any(), any());

Could you explain why changing from await() to sleep() made it work ? If temporal expects the workflow thread to not block, what is its purpose ?

Busy wait with Workflow.sleep is an anti-pattern. Workflow.await is the way to go. I believe the problem in your case caused by while loop spinning indefinitely when condition !Objects.isNull(result)) becomes true. I don’t understand why you need loop at all when using await. I would change it to:

Workflow.await(MAXIMUM_TIME_TO_WAIT_FOR_SIGNAL, () -> !Objects.isNull(result));

That makes sense… Thanks for the help :slight_smile:

I applied this pattern tweaking from the original HelloSignal example, so that’s why.

Regarding that implementation, would you say it is better to split the workflow in smaller bits ? End the first workflow when the file is submitted for processing and another one when I am signaled the end of it ? Would it make any difference in regards to temporal ?

Regarding that implementation, would you say it is better to split the workflow in smaller bits ? End the first workflow when the file is submitted for processing and another one when I am signaled the end of it ? Would it make any difference in regards to temporal ?

See this post.