Workflow.sleep() and CancellationScope usage on synchronous activities;

Hi Team,

I am working on a Temporal workflow that consists of five activities that need to be executed sequentially and all the activities are executing in synchronous way… The requirement is:

  1. When an activity starts and completes, I need to wait for a certain duration before notifying the user to complete the next activity.

  2. If the user completes the next activity before the threshold duration, the workflow should immediately proceed to the next activity instead of waiting for the full duration.

  3. If the activity is not completed within the threshold duration, a notification should be sent to remind the user until activity got completed.

  4. I tried implementing this using Workflow.sleep() and CancellationScope, but I was unable to achieve the desired behavior.

Approach Tried & Issues Faced

  1. Using Workflow.sleep()

The problem with Workflow.sleep() is that it blocks execution until the full sleep duration completes, even if the user completes the activity before that.

Since Workflow.sleep() is not interruptible, I couldn’t find a way to wake it up early when the activity is completed within the threshold time.

  1. Using CancellationScope

I attempted to run Workflow.sleep() inside a CancellationScope and cancel it when the activity completes.

However, it seems that Workflow.sleep() does not respond to cancellation in the expected way.

Code snippets:

while (!firstActivity) {
			Workflow.sleep(Duration.ofSeconds(10));
			// notify user
			super.notifyUsers("complete first activity");
		}
		Workflow.await(() -> firstActivity);
CancellationScope firstActivityScope = Workflow.newCancellationScope(() -> {
	            while (!firstActivity) {
	                
					Workflow.sleep(10000); 
					super.notifyUsers("complete first activity");
	            }
	        });
	 
	firstActivityScope .run(); 
	        Workflow.await(() -> firstActivity); 
	        firstActivityScope .cancel();

Thanks in advance for your insights!

Use Workflow.await(duration, condition). It is enough to not require sleep and cancellation.

Hi @maxim and Team,

I switched to using Workflow.await(Duration, condition), but I still don’t see the expected behavior.I am using a synchronous update method (@UpdateMethod) for manual validation.

Here’s the current code:

public class MyWorkflowImpl implements MyWorkflow {
   private boolean isManual = false;

   @Override
   public void runWorkflow() {
       log.info("Workflow started. Waiting for manual validation...");

       while (!isManual) {
           log.info("Sending notification to user...");
           super.notifyUsers("isManual");

           log.info("Waiting for manual validation or timeout...");
           boolean completed = Workflow.await(Duration.ofSeconds(10), () -> isManual);

           if (completed) {
               log.info("Manual validation received! Proceeding...");
               break;
           } else {
               log.info("Timeout reached, sending another notification...");
           }
       }

       log.info("Proceeding after manual validation");
   }

   @UpdateMethod
   @Override
   public String manualValidation(WorkflowRequest workflowRequest) {
       log.info("Manual validation method called!");
       this.isManual = true;
       log.info("isManual set to true. Workflow should proceed now.");
       return "Activity Completed"
   }
}

Issue I’m Facing:

  1. The notifications are being sent, but sometimes the workflow does not wake up immediately when manualValidation() is called.
    snap 1:-

snap 2:-

  1. Instead of exiting immediately when isManual = true, it waits for the full timeout before proceeding.

  2. It seems like Workflow.await() is not reacting to the @UpdateMethod update in real time.

Is this the correct way to achieve periodic notifications while also allowing an immediate exit when manual validation is received?

Does Workflow.await() not work well with @UpdateMethod, and should I use signals instead?

Would really appreciate any guidance or corrections on my approach!

Thanks in advance!

Snap 2 for reference: