Repository navigation
fix(sm): run an every-second schedule every second - #1070
Merged
janbjorge merged 1 commit intoOct 28, 2026
Merged
Conversation
janbjorge
force-pushed
the
fix/scheduler-second-schedules
branch
from
October 28, 2026 20:24
05859ba to
1b9f26d
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Agentic
Summary
SchedulerManager.runsleeps until the soonest schedule is due, plus a fixedleewayof one second. For a schedule that fires every second (* * * * * *, the 6-field form the scheduling guide documents), the next tick has already passed by the time the loop wakes.fetch_schedulethen movesnext_runto the first tick after now, so every other tick is skipped and the schedule runs every two seconds.It also shows up next to other schedules. The loop wakes for the soonest one, so with an every-second schedule registered, a
*/3schedule fired with gaps of 2 and 4 seconds instead of 3.I ran real
SchedulerManagers against PostgreSQL 16.2 for 12 seconds per run, on asyncpg and on psycopg, nothing mocked:PyPI 1.6.0 gives the same as main.
Change
pgqueuer/core/sm.py, +3/-1: the leeway goes from 1 s to 100 ms, under the one-second cron resolution, with a two-line comment. Plus aRELEASE.mdFixed entry.From reading the code, I don't think the full second was protecting against clock skew.
fetch_schedulesetsnext_runfrom the database's ownNOW()plus the same delay the loop then sleeps, and truncates it to the second, so the offset between the worker clock and the database clock cancels out. The leeway only has to cover the time between computing the delay and the query starting. I picked 100 ms. Anything under a second fixes this, so happy to use another value if you prefer.Testing
uv sync --frozen && uv run ruff check . && uv run ruff format . --check && uv run lint-imports && uv run mypy . && uv run pytestpassed (PostgreSQL 16.2 throughEXTERNAL_POSTGRES_DSN, Python 3.12, pytest as CI runs it with-n 3 --dist worksteal, mypy asmypy . --no-incremental): 1567 passed, 10 skipped, 2 xfailed, rebased on current main (5c2e7c1). Before the rebase, on 4d687d7: 1566 with the change and 1562 without (the 4 new tests are the difference).test_scheduler.pygets a helper that runs aSchedulerManageruntil a schedule has fired four times and returns the time from the first firing to the last, onInMemoryQueriesand onQueries(apgdriver).test_every_second_schedule_fires_every_second(and_postgres) expects under 4.5 s for* * * * * *. On main it takes 6.0 s and fails; with the fix it takes about 3 s.test_two_second_schedule_keeps_its_cadence(and_postgres) is the control:* * * * * */2still takes over 4.5 s, so the shorter wait does not make a schedule fire more often. It passes on main and with the fix. I checked the total time rather than each gap so a slow runner does not flip it; the four tests passed 5 runs in a row under-n 4.Checklist