MCPcopy
hub / github.com/codeaashu/claude-code / process

Function process

src/utils/cronScheduler.ts:248–345  ·  view source on GitHub ↗
(t: CronTask, isSession: boolean)

Source from the content-addressed store, hash-verified

246 // session tasks are removed synchronously from memory, file tasks go
247 // through the async removeCronTasks + chokidar reload.
248 function process(t: CronTask, isSession: boolean) {
249 if (filter && !filter(t)) return
250 seen.add(t.id)
251 if (inFlight.has(t.id)) return
252
253 let next = nextFireAt.get(t.id)
254 if (next === undefined) {
255 // First sight — anchor from lastFiredAt (recurring) or createdAt.
256 // Never-fired recurring tasks use createdAt: if isLoading delayed
257 // this tick past the fire time, anchoring from `now` would compute
258 // next-year for pinned crons (`30 14 27 2 *`). Fired-before tasks
259 // use lastFiredAt: the reschedule below writes `now` back to disk,
260 // so on next process spawn first-sight computes the SAME newNext we
261 // set in-memory here. Without this, a daemon child despawning on
262 // idle loses nextFireAt and the next spawn re-anchors from 10-day-
263 // old createdAt → fires every task every cycle.
264 next = t.recurring
265 ? (jitteredNextCronRunMs(
266 t.cron,
267 t.lastFiredAt ?? t.createdAt,
268 t.id,
269 jitterCfg,
270 ) ?? Infinity)
271 : (oneShotJitteredNextCronRunMs(
272 t.cron,
273 t.createdAt,
274 t.id,
275 jitterCfg,
276 ) ?? Infinity)
277 nextFireAt.set(t.id, next)
278 logForDebugging(
279 `[ScheduledTasks] scheduled ${t.id} for ${next === Infinity ? 'never' : new Date(next).toISOString()}`,
280 )
281 }
282
283 if (now < next) return
284
285 logForDebugging(
286 `[ScheduledTasks] firing ${t.id}${t.recurring ? ' (recurring)' : ''}`,
287 )
288 logEvent('tengu_scheduled_task_fire', {
289 recurring: t.recurring ?? false,
290 taskId:
291 t.id as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
292 })
293 if (onFireTask) {
294 onFireTask(t)
295 } else {
296 onFire(t.prompt)
297 }
298
299 // Aged-out recurring tasks fall through to the one-shot delete paths
300 // below (session tasks get synchronous removal; file tasks get the
301 // async inFlight/chokidar path). Fires one last time, then is removed.
302 const aged = isRecurringTaskAged(t, now, jitterCfg.recurringMaxAgeMs)
303 if (aged) {
304 const ageHours = Math.floor((now - t.createdAt) / 1000 / 60 / 60)
305 logForDebugging(

Callers 1

checkFunction · 0.70

Calls 13

jitteredNextCronRunMsFunction · 0.85
logForDebuggingFunction · 0.85
logEventFunction · 0.85
isRecurringTaskAgedFunction · 0.85
removeSessionCronTasksFunction · 0.85
removeCronTasksFunction · 0.85
getMethod · 0.65
deleteMethod · 0.65
addMethod · 0.45
hasMethod · 0.45
setMethod · 0.45

Tested by

no test coverage detected