From 9e71041a1c70e62625fbba4eca63f62bd43beb23 Mon Sep 17 00:00:00 2001 From: Pratyush Sharma <56130065+pratyush618@users.noreply.github.com> Date: Sun, 19 Jul 2026 02:03:31 +0530 Subject: [PATCH] fix(test): reread dead letters after codel test converges The poll loop read dead letters before stats, so a job shed between the two reads left a stale count when the exit condition fired. --- .../src/test/java/org/byteveda/taskito/core/CodelTest.java | 7 +++++++ sdks/node/test/core/codel.test.ts | 6 ++++++ sdks/python/tests/core/test_codel.py | 5 +++++ 3 files changed, 18 insertions(+) diff --git a/sdks/java/src/test/java/org/byteveda/taskito/core/CodelTest.java b/sdks/java/src/test/java/org/byteveda/taskito/core/CodelTest.java index 26b939c9..425f0b45 100644 --- a/sdks/java/src/test/java/org/byteveda/taskito/core/CodelTest.java +++ b/sdks/java/src/test/java/org/byteveda/taskito/core/CodelTest.java @@ -73,6 +73,13 @@ void shedsStaleJobsUnderOverload(@TempDir Path dir) throws Exception { Thread.sleep(100); } + // A job can be shed between the dead-letter read and the stats + // read that satisfied the exit condition; once converged nothing + // moves, so a fresh dead-letter read gives the settled count. + codelDead = queue.listDead(100, 0).stream() + .filter(d -> d.error != null && d.error.startsWith("codel:")) + .count(); + assertTrue(codelDead >= 1, "sustained overload should shed at least one stale job"); assertEquals(codelDead, stats.dead, "every dead job is a CoDel drop"); assertEquals(total, stats.completed + stats.dead, "no job is lost"); diff --git a/sdks/node/test/core/codel.test.ts b/sdks/node/test/core/codel.test.ts index 1994ea9f..81a902e1 100644 --- a/sdks/node/test/core/codel.test.ts +++ b/sdks/node/test/core/codel.test.ts @@ -62,6 +62,12 @@ it("sheds stale jobs to the DLQ under sustained overload", async () => { await sleep(100); } + // A job can be shed between the dead-letter read and the stats read that + // satisfied the exit condition; once converged nothing moves, so a fresh + // dead-letter read gives the settled count. + const dead = await queue.deadLetters(100); + codelDead = dead.filter((d) => (d.error ?? "").startsWith("codel:")).length; + expect(codelDead).toBeGreaterThanOrEqual(1); // Every dead job is a CoDel drop (the task never throws), and nothing is lost. expect(stats.dead).toBe(codelDead); diff --git a/sdks/python/tests/core/test_codel.py b/sdks/python/tests/core/test_codel.py index a2000fe9..88235c91 100644 --- a/sdks/python/tests/core/test_codel.py +++ b/sdks/python/tests/core/test_codel.py @@ -54,6 +54,11 @@ def slow() -> None: if stats["completed"] + stats["dead"] == total and len(codel_dead) >= 1: break time.sleep(0.1) + # A job can be shed between the dead-letter read and the stats read + # that satisfied the exit condition; once converged nothing moves, so + # a fresh dead-letter read gives the settled count. + dead = q.dead_letters(limit=100) + codel_dead = [d for d in dead if str(d.get("error", "")).startswith("codel:")] finally: q.shutdown() worker.join(timeout=5)