Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assumptions.assumeTrue;

import dev.dbos.transact.Constants;
import dev.dbos.transact.DBOS;
Expand Down Expand Up @@ -158,22 +159,41 @@ public void absoluteTimeoutFiresEvenIfCallsKeepArriving() throws Exception {
DebouncedService svc = dbos.registerProxy(DebouncedService.class, serviceImpl);
dbos.launch();

var dataSource = pgContainer.dataSource();
var debouncer = dbos.<String>debouncer().withDebounceTimeout(Duration.ofMillis(1500));

var first = debouncer.debounce("user-3", Duration.ofMillis(800), () -> svc.process("v1"));
String firstId = first.workflowId();

// Keep extending the period — the absolute timeout should still kick in.
long deadline = System.currentTimeMillis() + 3000;
while (System.currentTimeMillis() < deadline && serviceImpl.callCount() == 0) {
debouncer.debounce("user-3", Duration.ofMillis(800), () -> svc.process("vN"));
long prevCalledAt = System.currentTimeMillis();
var first = debouncer.debounce("user-3", Duration.ofMillis(800), () -> svc.process("v0"));
Long deadline = DebouncedRows.read(dataSource, first.workflowId()).debounceDeadlineEpochMs();
assertNotNull(deadline);

// Keep extending the period until a call's own period would end past the deadline, so the
// deadline, not that period, decides when the workflow runs. Stop there: the first sweep after
// the delay expires moves the workflow out of DELAYED and frees the key, and a call after that
// would start a fresh workflow.
String lastArg;
for (int i = 1; ; i++) {
String arg = "v" + i;
long calledAt = System.currentTimeMillis();
// The row holds the key at least until the previous call's period or the deadline ends,
// whichever is first. A pause that used up that window would let this call start a fresh
// workflow, so this run cannot test the scenario.
assumeTrue(
calledAt < Math.min(prevCalledAt + 800, deadline) - 200,
"paused past the window in which the key is held");
var handle = debouncer.debounce("user-3", Duration.ofMillis(800), () -> svc.process(arg));
Comment thread
devhawk marked this conversation as resolved.
assertEquals(first.workflowId(), handle.workflowId());
lastArg = arg;
if (calledAt + 800 > deadline) {
break;
}
prevCalledAt = calledAt;
Thread.sleep(150);
}

String result = first.getResult();
assertTrue(result.startsWith("result:"));
assertEquals("result:" + lastArg, first.getResult());
assertEquals(1, serviceImpl.callCount());
assertEquals(firstId, first.workflowId());
assertEquals(deadline, DebouncedRows.read(dataSource, first.workflowId()).delayUntilEpochMs());
}

@Test
Expand Down
Loading