v0.1.76 — 25 May 2026
Bug Fix — Cron jobs triggered from extensions now execute the current code
Who is affected: Anyone whose runtime extensions call
services.cron.trigger() or context.services.cron.trigger() to fire a cron
job.
What was wrong
Cron jobs triggered from an extension ran with the code that was compiled when
the server last started. Edits made to the cron job after startup were ignored
by extension-triggered runs, even hours later. Running the same job via the UI
“Run Now” button or the MCP run_now action always used the current code.
Root cause
Next.js splits server-side code into multiple webpack chunks at build time. The
CronManager module was evaluated separately in the startup chunk (which
initialises the scheduler) and in the API-route chunk (which handles saves and
manual triggers). This produced two independent CronManager instances, each
with its own compiled-handler cache.
When a cron job was saved, the save API called reloadJob() on the
API-route instance — updating that cache — while the startup instance
(used by the scheduler and by services.cron.trigger()) retained the old
compiled code from startup.
The RuntimeExtensionManager (for extensions) and the event emitter already
used a globalThis singleton pattern specifically to prevent this. CronManager
was missing the same treatment.
What changed
CronManager is now stored on globalThis, matching the pattern already used
by RuntimeExtensionManager. All execution paths — scheduled ticks, UI/MCP
triggers, and extension-triggered runs — share the same instance, so saving a
cron job always updates the cache used by every caller.
Before / After
| Trigger path | Before this fix | After this fix |
|---|---|---|
| Scheduled tick | ✅ Current code (startup cache) | ✅ Current code |
UI “Run Now” / MCP run_now | ✅ Current code (API cache) | ✅ Current code |
services.cron.trigger() from extension | ❌ Startup-time code (stale) | ✅ Current code |
Improvement — Timeout field now accepts any value above the minimum
Affected pages: Extension detail, Cron job detail.
The Timeout (ms) input previously enforced a hard upper limit in the UI
(30 s for extensions, 5 min for cron jobs). This cap has been removed.
The field now accepts any value above its minimum — 100 ms for extensions,
1 000 ms for cron — so operators can configure whatever execution window their
workloads require.