A durable countdown that posts a notification on each tick and sleeps between ticks. Demonstrates ctx.run durable steps and ctx.sleep against a Resonate dev server.
Heads up —
resonate-sdk-javais pre-release (v0.1.x). This example pinsio.resonatehq:resonate-sdk-java:0.1.1, the first published release on Maven Central. Expect API changes beforev1.0.
- A multi-step durable workflow: each tick runs a step and then sleeps.
ctx.sleep(Duration)— a durable sleep that can suspend for seconds, hours, or days and resume exactly where it left off after a crash.- Crash resilience: restart the worker mid-countdown and already-sent ticks short-circuit instead of replaying.
public static int countdown(Context ctx, int start, int stepSeconds) {
int sent = 0;
for (int i = start; i > 0; i--) {
ctx.run(Countdown::tick, i).await(); // durable step
sent++;
if (i > 1) {
ctx.sleep(Duration.ofSeconds(stepSeconds)).await(); // durable sleep
}
}
return sent;
}
public static String tick(Context ctx, int count) {
System.out.println(" [tick] " + count);
return "ok";
}tick is wrapped in ctx.run so its result is recorded in a durable promise. The side effect (the println) lives in the leaf, which settles once and never re-runs — so on resume after a crash, already-sent ticks are not re-printed.
- Java 21+ — the SDK uses virtual threads, a Java 21 feature. Java 8/11/17 will not work.
- The
resonateserver CLI:Other install paths: https://docs.resonatehq.io/get-started/quickstart.brew install resonatehq/tap/resonate
git clone https://github.com/resonatehq-examples/example-countdown-java.git
cd example-countdown-javaIn one terminal, start the dev server:
resonate devIn another, run the example (defaults to start=3, one second between ticks):
./gradlew runPass your own start + step (seconds):
./gradlew run --args="5 2"Expected output for the default run:
[countdown] starting workflow id=countdown-... start=3 step=1s
[tick] 3
[tick] 2
[tick] 1
[countdown] done; sent 3 notifications
While a longer countdown is running (e.g. --args="5 10"), inspect the durable promises with resonate tree <id> — each tick is a resolved run promise and each gap is a sleep promise. Kill the worker mid-countdown and restart it: the countdown resumes from the pending sleep rather than starting over.
example-countdown-java/
├── src/main/java/io/resonatehq/examples/countdown/Countdown.java
├── build.gradle.kts dependencies + Java 21 toolchain + main class
├── settings.gradle.kts project name
├── gradlew, gradle/ Gradle wrapper
├── LICENSE Apache-2.0
└── README.md
example-quickstart-java— the same countdown, invoked from the CLI.- Durable execution concepts — what makes sleep and steps durable.
- Java SDK docs — the full Java API surface.
- Discord: https://resonatehq.io/discord
- X: https://x.com/resonatehqio
- LinkedIn: https://www.linkedin.com/company/resonatehqio
- YouTube: https://www.youtube.com/@resonatehqio
- Journal: https://journal.resonatehq.io