You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[FIX] CI cron: skip a run while the previous one is still running - #1247
I have checked that another pull request for this purpose does not exist.
I have considered, and confirmed that this submission will be valuable to others.
I accept that this submission may not be used, and the pull request closed at the will of the maintainer.
I give this submission freely, and claim no ownership to its content.
My familiarity with the project is as follows (check one):
I have never used the project.
I have used the project briefly.
I have used the project extensively, but have not contributed previously.
I am an active contributor to the project.
Problem
Since 2026-10-25 06:07 UTC, no test can start: /repository returns Transport endpoint is not connected. The VM ran out of memory, and the kernel's OOM killer killed gcsfuse:
06:07:33 systemd[1]: repository.mount: A process of this unit has been killed by the OOM killer.
06:07:34 kernel: Out of memory: Killed process 673 (gcsfuse) ...
Before that, from 00:48 UTC, it had killed mysqld 17 times.
Root Cause
Cron starts cron.py every 10 minutes, and nothing stops two runs from overlapping.
While the queue was stuck: each run ended within seconds, so runs didn't overlap.
At every OOM kill on Oct 25: 2–4 cron processes were running, using 425–634 MB together, on a VM with 2 GB of RAM and no swap.
Fix
cron() takes a non-blocking fcntl.flock on a lock file in the temp directory. If a previous run still holds it, the new run logs a warning and exits. The kernel releases the lock when the process exits, even if it's killed.
The change is in cron.py, so the normal deploy picks it up and the crontab doesn't change.
Test
Unit test:test_cron_job_skips_while_previous_run_holds_lock. With the lock held, cron() doesn't call start_platforms and logs the warning. Fork CI run: 808 tests OK on Python 3.12–3.15, and all code checks pass.
Real processes on Ubuntu 24.04, running this cron.py with the platform modules stubbed and start_platforms sleeping:
A second run started during the first is skipped.
After the first run is killed with SIGKILL, the next run takes the lock.
After a normal finish, the next run proceeds.
Note
The bucket still needs to be remounted on the VM. It's best done after this is deployed, so the backlog doesn't fill the memory again.
Took a look through mod_ci/cron.py and the test additions. Preventing overlapping cron runs to avoid OOM killer spikes on low-memory VMs makes complete sense.
A couple of small notes from looking at the implementation:
import fcntl is imported at module top-level in mod_ci/cron.py. Since fcntl is Unix-only, this raises ModuleNotFoundError for contributors running or testing on Windows. Wrapping it with a fallback guard (e.g. try: import fcntl except ImportError: fcntl = None) ensures it won't break local development environments.
In cron(), open(LOCK_FILE, w) truncates the lockfile on each invocation. Opening in append or read/write mode (a or os.O_CREAT | os.O_RDWR) avoids modifying/truncating the file while another process holds an active lock.
When cron() completes normally, lock.close() is never called, so the file descriptor relies on GC or process exit to release. Wrapping the core cron body in a try...finally block to call lock.close() keeps cleanup explicit.
Overall a very clean and needed fix for the queue backlog.
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
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.
In raising this pull request, I confirm the following (please check boxes):
My familiarity with the project is as follows (check one):
Problem
Since 2026-10-25 06:07 UTC, no test can start:
/repositoryreturnsTransport endpoint is not connected. The VM ran out of memory, and the kernel's OOM killer killed gcsfuse:Before that, from 00:48 UTC, it had killed
mysqld17 times.Root Cause
Cron starts
cron.pyevery 10 minutes, and nothing stops two runs from overlapping.Fix
cron()takes a non-blockingfcntl.flockon a lock file in the temp directory. If a previous run still holds it, the new run logs a warning and exits. The kernel releases the lock when the process exits, even if it's killed.The change is in
cron.py, so the normal deploy picks it up and the crontab doesn't change.Test
test_cron_job_skips_while_previous_run_holds_lock. With the lock held,cron()doesn't callstart_platformsand logs the warning. Fork CI run: 808 tests OK on Python 3.12–3.15, and all code checks pass.cron.pywith the platform modules stubbed andstart_platformssleeping:SIGKILL, the next run takes the lock.Note
The bucket still needs to be remounted on the VM. It's best done after this is deployed, so the backlog doesn't fill the memory again.