Skip to content

Commit d0e4b34

Browse files
authored
test(workflow): make rate-limit burst and refill checks deterministic (#7433)
1 parent 38a30fc commit d0e4b34

1 file changed

Lines changed: 25 additions & 16 deletions

File tree

‎tests/units/reflex_workflow/engine/test_runner.py‎

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2005,27 +2005,36 @@ async def test_a_worker_with_one_slot_still_visits_every_table(session_factory):
20052005
await engine.dispose()
20062006

20072007

2008-
async def test_a_rate_limit_lets_through_a_burst_then_refills(session_factory):
2008+
@pytest.mark.parametrize("enqueue_delay", [0, 1.1])
2009+
async def test_a_rate_limit_lets_through_a_burst_then_refills(
2010+
session_factory, monkeypatch, enqueue_delay
2011+
):
2012+
"""A full bucket allows a burst and a partial refill allows two more runs."""
20092013
STARTS.clear()
20102014
provider = f"provider-{uuid.uuid4().hex}"
2011-
started = time.monotonic()
2015+
# Four tokens per hour prevent setup or scheduling delays from refilling
2016+
# the bucket; backdating it by half an hour releases exactly two tokens.
2017+
period = datetime.timedelta(hours=1)
2018+
monkeypatch.setattr(
2019+
Metered, "__workflow_limit__", Limit(by="provider", rate=4, per=period)
2020+
)
2021+
await asyncio.sleep(enqueue_delay)
20122022
await start_many(Metered, provider, 8, provider=provider)
20132023

2014-
async def all_done() -> bool:
2015-
"""Tell whether every run has finished.
2016-
2017-
Returns:
2018-
Whether it has.
2019-
"""
2024+
for expected in (4, 6, 8):
2025+
if expected > 4:
2026+
async with session_factory() as session, session.begin():
2027+
await session.execute(
2028+
update(WorkflowRate)
2029+
.where(WorkflowRate.key == claim.bucket_key(Metered, provider))
2030+
.values(tokens=0, updated_at=func.now() - period / 2)
2031+
)
2032+
# A settled worker has finished its steps and found no more to claim.
2033+
assert await runner.wake(datetime.timedelta(seconds=30))
2034+
assert len(STARTS[provider]) == expected
20202035
rows = await Metered.by(Metered.provider == provider).all()
2021-
return len(rows) == 8 and all(row.status == "done" for row in rows)
2022-
2023-
await wait_until(all_done, timeout=60)
2024-
times = sorted(t - started for t in STARTS[provider])
2025-
# Four at once from a full bucket, then the rest as it refills: two a second.
2026-
assert len(times) == 8
2027-
assert times[3] < 1
2028-
assert times[7] >= 1.5
2036+
assert len(rows) == 8
2037+
assert sum(row.status == "done" for row in rows) == expected
20292038

20302039

20312040
async def test_a_rate_limit_holds_across_workers(session_factory):

0 commit comments

Comments
 (0)