Invite-only beta · 9 free places left · Managed hosting on AWS

AceMedia HostTalk to us

OPERATIONS · 8 NOVEMBER 2026

Cron locks stop overlapping runs. Make sure they do not hide skipped ones

Cron locks around scheduled jobs keep runs from stacking up on a shared database. On AceHost that worked. It also let a background lease skip thousands of runs without anyone noticing, and a shared lock I added later caused more trouble than it solved.

Most WordPress sites on AceHost run their scheduled tasks from the system cron rather than from visitors' requests. Every five minutes, each site's user runs WP-CLI to process whatever is due. The sites share one managed MySQL database.

After a database incident earlier this year, the cause was easy to see in hindsight. Some runs had grown slower than the gap between them. A new run started before the last one finished, each held a database connection, and the connections ran out.

Cron locks: one per site

The fix is a lock around each run:

*/5 * * * * flock -n /run/lock/wpcron-example.lock wp cron event run --due-now --quiet

flock -n gives up straight away if the previous run is still going, so runs never stack. Each lock file is created by the site's own user, so there are no permission problems between sites. I also offset each site's schedule by a couple of minutes so they do not all start together.

The shared lock I removed

I also built a second, shared lock so that sites would queue for the database rather than all hit it at once. Once the real causes of the slow runs were fixed, runs dropped from over two minutes to a few seconds, and the shared lock was doing more harm than good:

  • It coupled the sites. One slow site made every other site wait, or time out.
  • It needed a root-owned, world-writable lock file and a rule to recreate it after reboots, because /run/lock is cleared.
  • It had a silent failure. /run/lock is shared by every user. Whichever site's user created the lock file first owned it, and the others could not open it. "Sites queue politely" quietly became "one site never waits".

I took it out and wrote down when it would be worth bringing back: if runs grow past two minutes again, or if there are too many sites for the offsets to keep them apart.

A lease that skipped quietly

Some heavier background jobs go through a separate budget wrapper. It takes a single non-blocking lease, so only so much background work runs at once. If it cannot get the lease, it exits with success and writes a line to the system journal.

That sounded sensible. When I finally counted, one site had recorded 2,673 skips against 1,500 starts over about a week. The job's own log showed nothing wrong, because the job never started. The skips were only in the journal, which nobody was reading.

A related problem made it worse. One job's cron line had stopped running entirely, but its heartbeat was still recent enough that WordPress's own cron stood down, assuming the system cron had it covered. For a day, nothing generated that content at all.

Check this on your own server: if a job is wrapped in a lock or lease, look at the wrapper's output as well as the job's log. A skipped run and a successful run can look identical.

Schedules shorter than the trigger

One more detail. If WordPress cron is disabled and the system cron fires every five minutes, an event registered as "every minute" can only run every five. Plugins declare schedules like that all the time. The declared schedule is not the real one.

What I check now

  1. Each site's runs are locked so they cannot stack.
  2. Runs are short enough that the lock rarely matters.
  3. Skips are counted and reported, not just logged.
  4. A heartbeat only counts if the job behind it actually ran.
  5. Declared schedules are compared with how often the trigger really fires.

This follows on from checking that scheduled WordPress jobs finish. Locks solve the overlap. They do not tell you the work happened.

More hosting tipsManaged hosting

INVITE-ONLY BETA

Tell us about your site.

Nine free hosting beta invites remain for open-source projects, charities, community organisations and other public-benefit work. Tell us what you’re building; we’ll review the fit and reply personally. Fields marked * are required.

Please do not send passwords or private customer data. We’ll use these details to reply. Privacy notice.

Prefer email? Write to [email protected].