Manual Time Skipping

Hello,

I am researching how to use manual time skipping when testing Workflow code. When I look at the documentation, I only see "Learn to skip time manually in the SDK of your choice." Could someone elaborate or point me to an example on how to use time skipping manually in Java?

Thanks!

1 Like

Java SDK doesn’t support manual time skipping. It skips the time automatically when the workflow under test is blocked.

2 Likes

What does the .sleep(duration Duration) function do then?

It forwards time forward.

How is that different from “manually skipping time”?

I have the same question, and the docs in the Java SDK section need work here. The docs should not say “Learn to skip time manually in the SDK of your choice.” when I’m already looking at the “Java SDK” section. :slight_smile:

and

Can we have some clarification under which conditions time is skipped automatically and under which conditions we need to call sleep to move time forward?

The sleep function blocks the workflow code. So, the time is automatically moved forward to unblock the workflow. I wouldn’t call it “manual time skipping.”

After doing some local testing and looking through the source code, I think I understand how it works.

I tested it locally with a simple workflow that looks like this:

class TimeSkipWorkflowImpl : TimeSkipWorkflow {
  private val logger = wfLogger()

  private var cond: Boolean = false

  override fun start() {
    logger.info("Starting, awaiting up to 1 day for cond")
    val awaitResult = Workflow.await(1.days.toJavaDuration()) { cond }
    logger.info("Await done, cond = $cond, awaitResult = $awaitResult")
  }

  override fun setCond() {
    cond = true
  }

And I see that when I execute the workflow, it blocks at the Workflow.await until I either do one of two things:

  1. I do TestEnvironment.sleep for more than 1 day to trigger the timeout, OR
  2. I send the setCond signal, OR
  3. I request a result from the workflow.

The first and second behavior makes perfect sense for testing. The third behavior was surprising to me, but also makes sense for testing, and is consistent with the statement:

It skips the time automatically when the workflow under test is blocked.

Looking at the code, I see that the test service has a “time locking counter”. This counter allows the test code to switch between moving time forward “normally” (real-time pace), or to skip time.

The test workflow starts out with time skipping locked/disabled. The workflow will therefore proceed at real-time, allowing the first and second behaviors above to work as expected.

However, when behavior three is run, the test environment has explicit logic to decrement the “time locking counter”, which unlocks/activates time skipping and allows the await to complete/timeout. Once the result has been obtained, the test environment increments the counter and therefore locks/deactivates time skipping again.

The fact that it is a counter allows multiple test threads to do this safely.

And of course time skipping can be disabled in the TestWorkflowEnvironment via setting useTimeskipping in the TestEnvironmentOptions to false. This simply increments the counter on environment startup so that time skipping never unlocks/activates.

Useful code references:

All the calls to unlock time skipping are from calls to get a result from the workflow. All the calls to lock time skipping are after the result has been obtained.

1 Like