@grackle-ai/core 0.79.0 → 0.79.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{cron-manager.d.ts → cron-phase.d.ts} +12 -29
- package/dist/cron-phase.d.ts.map +1 -0
- package/dist/cron-phase.js +116 -0
- package/dist/cron-phase.js.map +1 -0
- package/dist/find-connected-environment.d.ts +1 -1
- package/dist/find-connected-environment.js +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/reconciliation-manager.d.ts +37 -0
- package/dist/reconciliation-manager.d.ts.map +1 -0
- package/dist/reconciliation-manager.js +98 -0
- package/dist/reconciliation-manager.js.map +1 -0
- package/package.json +7 -7
- package/dist/cron-manager.d.ts.map +0 -1
- package/dist/cron-manager.js +0 -167
- package/dist/cron-manager.js.map +0 -1
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Cron reconciliation phase — fires due schedules on each tick.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Extracted from the former CronManager so it can plug into the
|
|
5
|
+
* ReconciliationManager as one of several ordered phases.
|
|
6
6
|
*/
|
|
7
7
|
import type { ScheduleRow, EnvironmentRow, TaskRow } from "@grackle-ai/database";
|
|
8
8
|
import type { GrackleEventType } from "./event-bus.js";
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
import type { ReconciliationPhase } from "./reconciliation-manager.js";
|
|
10
|
+
/** Dependencies injected into the cron phase for testability. */
|
|
11
|
+
export interface CronPhaseDeps {
|
|
11
12
|
/** Query the schedule store for due entries. */
|
|
12
13
|
getDueSchedules: () => ScheduleRow[];
|
|
13
14
|
/** Advance a schedule after firing (update lastRunAt, nextRunAt, runCount). */
|
|
@@ -40,28 +41,10 @@ export interface CronManagerDeps {
|
|
|
40
41
|
isEnvironmentConnected: (environmentId: string) => boolean;
|
|
41
42
|
}
|
|
42
43
|
/**
|
|
43
|
-
*
|
|
44
|
+
* Create a ReconciliationPhase that fires due schedules.
|
|
45
|
+
*
|
|
46
|
+
* @param deps - Injected dependencies
|
|
47
|
+
* @returns A phase to register with ReconciliationManager
|
|
44
48
|
*/
|
|
45
|
-
export declare
|
|
46
|
-
|
|
47
|
-
private readonly checkIntervalMs;
|
|
48
|
-
private timer;
|
|
49
|
-
private ticking;
|
|
50
|
-
private tickPromise;
|
|
51
|
-
/**
|
|
52
|
-
* @param deps - Injected dependencies
|
|
53
|
-
* @param checkIntervalMs - How often to check for due schedules (default 10s)
|
|
54
|
-
*/
|
|
55
|
-
constructor(deps: CronManagerDeps, checkIntervalMs?: number);
|
|
56
|
-
/** Start the periodic ticker. */
|
|
57
|
-
start(): void;
|
|
58
|
-
/** Stop the ticker and await any in-flight tick. */
|
|
59
|
-
stop(): Promise<void>;
|
|
60
|
-
/** Attempt a tick, skipping if a previous tick is still in-flight. */
|
|
61
|
-
private tryTick;
|
|
62
|
-
/** Execute one tick: query due schedules and fire each. */
|
|
63
|
-
private tick;
|
|
64
|
-
/** Fire a single schedule: create task, start session, advance. */
|
|
65
|
-
private fireSchedule;
|
|
66
|
-
}
|
|
67
|
-
//# sourceMappingURL=cron-manager.d.ts.map
|
|
49
|
+
export declare function createCronPhase(deps: CronPhaseDeps): ReconciliationPhase;
|
|
50
|
+
//# sourceMappingURL=cron-phase.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cron-phase.d.ts","sourceRoot":"","sources":["../src/cron-phase.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AACjF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAGvE,iEAAiE;AACjE,MAAM,WAAW,aAAa;IAC5B,gDAAgD;IAChD,eAAe,EAAE,MAAM,WAAW,EAAE,CAAC;IACrC,+EAA+E;IAC/E,eAAe,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5E,2CAA2C;IAC3C,UAAU,EAAE,CACV,EAAE,EAAE,MAAM,EACV,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EAAE,EACnB,aAAa,EAAE,MAAM,EACrB,YAAY,CAAC,EAAE,MAAM,EACrB,YAAY,CAAC,EAAE,OAAO,EACtB,gBAAgB,CAAC,EAAE,MAAM,KACtB,IAAI,CAAC;IACV,wCAAwC;IACxC,iBAAiB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAChE,yEAAyE;IACzE,gBAAgB,EAAE,CAChB,EAAE,EAAE,SAAS,EACb,IAAI,EAAE,OAAO,EACb,OAAO,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,aAAa,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,KACrE,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACjC,2BAA2B;IAC3B,IAAI,EAAE,CAAC,IAAI,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IACzE,4DAA4D;IAC5D,6BAA6B,EAAE,MAAM,cAAc,GAAG,SAAS,CAAC;IAChE,+BAA+B;IAC/B,UAAU,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAC;IACtF,0DAA0D;IAC1D,OAAO,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,GAAG,SAAS,CAAC;IAC7C,mEAAmE;IAEnE,kBAAkB,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IACrF,4CAA4C;IAC5C,sBAAsB,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,OAAO,CAAC;CAC5D;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,aAAa,GAAG,mBAAmB,CAcxE"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cron reconciliation phase — fires due schedules on each tick.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from the former CronManager so it can plug into the
|
|
5
|
+
* ReconciliationManager as one of several ordered phases.
|
|
6
|
+
*/
|
|
7
|
+
import { v4 as uuidv4 } from "uuid";
|
|
8
|
+
import { logger } from "./logger.js";
|
|
9
|
+
import { computeNextRunAt } from "./schedule-expression.js";
|
|
10
|
+
import { ROOT_TASK_ID } from "@grackle-ai/common";
|
|
11
|
+
/**
|
|
12
|
+
* Create a ReconciliationPhase that fires due schedules.
|
|
13
|
+
*
|
|
14
|
+
* @param deps - Injected dependencies
|
|
15
|
+
* @returns A phase to register with ReconciliationManager
|
|
16
|
+
*/
|
|
17
|
+
export function createCronPhase(deps) {
|
|
18
|
+
return {
|
|
19
|
+
name: "cron",
|
|
20
|
+
execute: async () => {
|
|
21
|
+
const due = deps.getDueSchedules();
|
|
22
|
+
if (due.length === 0) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
logger.debug({ count: due.length }, "Cron phase: due schedules");
|
|
26
|
+
for (const schedule of due) {
|
|
27
|
+
await fireSchedule(deps, schedule);
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
/** Fire a single schedule: create task, start session, advance. */
|
|
33
|
+
async function fireSchedule(deps, schedule) {
|
|
34
|
+
const now = new Date().toISOString();
|
|
35
|
+
let nextRunAt;
|
|
36
|
+
try {
|
|
37
|
+
// Anchor to the schedule's lastRunAt (not current time) to prevent drift
|
|
38
|
+
nextRunAt = computeNextRunAt(schedule.scheduleExpression, schedule.lastRunAt ?? undefined);
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
logger.error({ scheduleId: schedule.id, scheduleExpression: schedule.scheduleExpression, err }, "Cron phase: failed to compute nextRunAt; disabling schedule");
|
|
42
|
+
// Disable the schedule to prevent error loop on every tick
|
|
43
|
+
deps.setScheduleEnabled(schedule.id, false, null);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
try {
|
|
47
|
+
// Resolve environment — check connectivity before creating tasks to avoid orphan tasks
|
|
48
|
+
let environmentId;
|
|
49
|
+
if (schedule.environmentId) {
|
|
50
|
+
// Explicit environment: verify it's connected before creating a task
|
|
51
|
+
if (!deps.isEnvironmentConnected(schedule.environmentId)) {
|
|
52
|
+
logger.warn({ scheduleId: schedule.id, environmentId: schedule.environmentId }, "Schedule fire skipped: specified environment not connected");
|
|
53
|
+
deps.advanceSchedule(schedule.id, now, nextRunAt);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
environmentId = schedule.environmentId;
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
// Auto-select first connected environment
|
|
60
|
+
const env = deps.findFirstConnectedEnvironment();
|
|
61
|
+
if (!env) {
|
|
62
|
+
logger.warn({ scheduleId: schedule.id }, "Schedule fire skipped: no connected environment");
|
|
63
|
+
deps.advanceSchedule(schedule.id, now, nextRunAt);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
environmentId = env.id;
|
|
67
|
+
}
|
|
68
|
+
// Validate persona exists
|
|
69
|
+
const persona = deps.getPersona(schedule.personaId);
|
|
70
|
+
if (!persona) {
|
|
71
|
+
logger.warn({ scheduleId: schedule.id, personaId: schedule.personaId }, "Schedule fire skipped: persona not found");
|
|
72
|
+
deps.advanceSchedule(schedule.id, now, nextRunAt);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
// Create task
|
|
76
|
+
const taskId = uuidv4();
|
|
77
|
+
const taskTitle = `${schedule.title} @ ${now}`;
|
|
78
|
+
const parentTaskId = schedule.parentTaskId || ROOT_TASK_ID;
|
|
79
|
+
deps.createTask(taskId, schedule.workspaceId || undefined, taskTitle, schedule.description, [], // no dependencies
|
|
80
|
+
"", // no workspace slug
|
|
81
|
+
parentTaskId, false, // canDecompose
|
|
82
|
+
schedule.personaId);
|
|
83
|
+
deps.setTaskScheduleId(taskId, schedule.id);
|
|
84
|
+
// Fetch the created task for startTaskSession
|
|
85
|
+
const task = deps.getTask(taskId);
|
|
86
|
+
if (!task) {
|
|
87
|
+
logger.error({ scheduleId: schedule.id, taskId }, "Schedule fire failed: created task not found");
|
|
88
|
+
deps.advanceSchedule(schedule.id, now, nextRunAt);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
// Start the task session
|
|
92
|
+
const error = await deps.startTaskSession(undefined, task, {
|
|
93
|
+
environmentId,
|
|
94
|
+
personaId: schedule.personaId,
|
|
95
|
+
});
|
|
96
|
+
// Advance schedule regardless of session start outcome
|
|
97
|
+
deps.advanceSchedule(schedule.id, now, nextRunAt);
|
|
98
|
+
if (error) {
|
|
99
|
+
logger.warn({ scheduleId: schedule.id, taskId, error }, "Schedule fire: task created but session start failed");
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
// Emit event only on successful fire
|
|
103
|
+
deps.emit("schedule.fired", {
|
|
104
|
+
scheduleId: schedule.id,
|
|
105
|
+
taskId,
|
|
106
|
+
firedAt: now,
|
|
107
|
+
});
|
|
108
|
+
logger.info({ scheduleId: schedule.id, taskId, title: schedule.title }, "Schedule fired");
|
|
109
|
+
}
|
|
110
|
+
catch (err) {
|
|
111
|
+
logger.error({ scheduleId: schedule.id, err }, "Schedule fire failed with exception");
|
|
112
|
+
// Still advance to prevent retry storms
|
|
113
|
+
deps.advanceSchedule(schedule.id, now, nextRunAt);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=cron-phase.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cron-phase.js","sourceRoot":"","sources":["../src/cron-phase.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Find the first connected environment, preferring local adapters.
|
|
3
3
|
*
|
|
4
4
|
* Extracted from the root task boot listener in server/src/index.ts
|
|
5
|
-
* so that
|
|
5
|
+
* so that the cron phase and other server-internal code can reuse the logic.
|
|
6
6
|
*/
|
|
7
7
|
import { type EnvironmentRow } from "@grackle-ai/database";
|
|
8
8
|
/**
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Find the first connected environment, preferring local adapters.
|
|
3
3
|
*
|
|
4
4
|
* Extracted from the root task boot listener in server/src/index.ts
|
|
5
|
-
* so that
|
|
5
|
+
* so that the cron phase and other server-internal code can reuse the logic.
|
|
6
6
|
*/
|
|
7
7
|
import { envRegistry } from "@grackle-ai/database";
|
|
8
8
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -10,8 +10,10 @@ export { attemptReconnects, resetReconnectState } from "./auto-reconnect.js";
|
|
|
10
10
|
export { pushToEnv } from "./token-push.js";
|
|
11
11
|
export { computeTaskStatus } from "./compute-task-status.js";
|
|
12
12
|
export { isKnowledgeEnabled, initKnowledge } from "./knowledge-init.js";
|
|
13
|
-
export {
|
|
14
|
-
export type {
|
|
13
|
+
export { ReconciliationManager } from "./reconciliation-manager.js";
|
|
14
|
+
export type { ReconciliationPhase } from "./reconciliation-manager.js";
|
|
15
|
+
export { createCronPhase } from "./cron-phase.js";
|
|
16
|
+
export type { CronPhaseDeps } from "./cron-phase.js";
|
|
15
17
|
export { findFirstConnectedEnvironment } from "./find-connected-environment.js";
|
|
16
18
|
export { validateExpression, computeNextRunAt } from "./schedule-expression.js";
|
|
17
19
|
export { checkVersionStatus, clearVersionCache, type VersionStatus } from "./version-check.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAG1D,OAAO,EACL,eAAe,EAAE,UAAU,EAC3B,aAAa,EAAE,aAAa,EAAE,gBAAgB,EAAE,eAAe,EAC/D,cAAc,EAAE,aAAa,GAC9B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAGzD,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAGjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAGtD,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAGlE,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC7E,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAG7D,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAGxE,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAG1D,OAAO,EACL,eAAe,EAAE,UAAU,EAC3B,aAAa,EAAE,aAAa,EAAE,gBAAgB,EAAE,eAAe,EAC/D,cAAc,EAAE,aAAa,GAC9B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAGzD,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAGjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAGtD,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAGlE,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC7E,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAG7D,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAGxE,OAAO,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AACpE,YAAY,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AACvE,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,YAAY,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,6BAA6B,EAAE,MAAM,iCAAiC,CAAC;AAChF,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAGhF,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,KAAK,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAG/F,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAGrC,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AACvC,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -17,8 +17,9 @@ export { pushToEnv } from "./token-push.js";
|
|
|
17
17
|
export { computeTaskStatus } from "./compute-task-status.js";
|
|
18
18
|
// ─── Knowledge ─────────────────────────────────────────────
|
|
19
19
|
export { isKnowledgeEnabled, initKnowledge } from "./knowledge-init.js";
|
|
20
|
-
// ───
|
|
21
|
-
export {
|
|
20
|
+
// ─── Reconciliation / Scheduling ──────────────────────────
|
|
21
|
+
export { ReconciliationManager } from "./reconciliation-manager.js";
|
|
22
|
+
export { createCronPhase } from "./cron-phase.js";
|
|
22
23
|
export { findFirstConnectedEnvironment } from "./find-connected-environment.js";
|
|
23
24
|
export { validateExpression, computeNextRunAt } from "./schedule-expression.js";
|
|
24
25
|
// ─── Version Check ────────────────────────────────────────
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAE1D,8DAA8D;AAC9D,OAAO,EACL,eAAe,EAAE,UAAU,EAC3B,aAAa,EAAE,aAAa,EAAE,gBAAgB,EAAE,eAAe,EAC/D,cAAc,EAAE,aAAa,GAC9B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAEzD,8DAA8D;AAC9D,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAEjD,8DAA8D;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAEtD,8DAA8D;AAC9D,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAElE,8DAA8D;AAC9D,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC7E,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAE7D,8DAA8D;AAC9D,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAExE,6DAA6D;AAC7D,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAE1D,8DAA8D;AAC9D,OAAO,EACL,eAAe,EAAE,UAAU,EAC3B,aAAa,EAAE,aAAa,EAAE,gBAAgB,EAAE,eAAe,EAC/D,cAAc,EAAE,aAAa,GAC9B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAEzD,8DAA8D;AAC9D,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAEjD,8DAA8D;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAEtD,8DAA8D;AAC9D,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAElE,8DAA8D;AAC9D,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC7E,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAE7D,8DAA8D;AAC9D,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAExE,6DAA6D;AAC7D,OAAO,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AAEpE,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAElD,OAAO,EAAE,6BAA6B,EAAE,MAAM,iCAAiC,CAAC;AAChF,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAEhF,6DAA6D;AAC7D,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAsB,MAAM,oBAAoB,CAAC;AAE/F,8DAA8D;AAC9D,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,8DAA8D;AAC9D,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AACvC,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ReconciliationManager — periodic ticker that runs ordered phases on each tick.
|
|
3
|
+
*
|
|
4
|
+
* Generalized from CronManager to support pluggable phases (cron, dispatch,
|
|
5
|
+
* stall detection, etc.) in a single background loop.
|
|
6
|
+
*/
|
|
7
|
+
/** A named async phase that runs during each reconciliation tick. */
|
|
8
|
+
export interface ReconciliationPhase {
|
|
9
|
+
/** Short name for logging (e.g. "cron", "dispatch"). */
|
|
10
|
+
name: string;
|
|
11
|
+
/** Execute the phase. Errors are caught by the manager — they don't abort the tick. */
|
|
12
|
+
execute: () => Promise<void>;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Periodic reconciliation manager that runs ordered phases on a configurable interval.
|
|
16
|
+
*/
|
|
17
|
+
export declare class ReconciliationManager {
|
|
18
|
+
private readonly phases;
|
|
19
|
+
private readonly tickIntervalMs;
|
|
20
|
+
private timer;
|
|
21
|
+
private ticking;
|
|
22
|
+
private tickPromise;
|
|
23
|
+
/**
|
|
24
|
+
* @param phases - Ordered list of phases to run on each tick
|
|
25
|
+
* @param tickIntervalMs - Override tick interval (default: GRACKLE_RECONCILIATION_TICK_MS env var or 10s)
|
|
26
|
+
*/
|
|
27
|
+
constructor(phases: ReconciliationPhase[], tickIntervalMs?: number);
|
|
28
|
+
/** Start the periodic ticker. */
|
|
29
|
+
start(): void;
|
|
30
|
+
/** Stop the ticker and await any in-flight tick. */
|
|
31
|
+
stop(): Promise<void>;
|
|
32
|
+
/** Attempt a tick, skipping if a previous tick is still in-flight. */
|
|
33
|
+
private tryTick;
|
|
34
|
+
/** Execute one tick: run each phase sequentially, isolating errors. */
|
|
35
|
+
private tick;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=reconciliation-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reconciliation-manager.d.ts","sourceRoot":"","sources":["../src/reconciliation-manager.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH,qEAAqE;AACrE,MAAM,WAAW,mBAAmB;IAClC,wDAAwD;IACxD,IAAI,EAAE,MAAM,CAAC;IACb,uFAAuF;IACvF,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B;AAED;;GAEG;AACH,qBAAa,qBAAqB;IAChC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAwB;IAC/C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IACxC,OAAO,CAAC,KAAK,CAA6C;IAC1D,OAAO,CAAC,OAAO,CAAkB;IACjC,OAAO,CAAC,WAAW,CAA4B;IAE/C;;;OAGG;gBACgB,MAAM,EAAE,mBAAmB,EAAE,EAAE,cAAc,CAAC,EAAE,MAAM;IAwBzE,iCAAiC;IAC1B,KAAK,IAAI,IAAI;IAepB,oDAAoD;IACvC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAWlC,sEAAsE;YACxD,OAAO;IAgBrB,uEAAuE;YACzD,IAAI;CASnB"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ReconciliationManager — periodic ticker that runs ordered phases on each tick.
|
|
3
|
+
*
|
|
4
|
+
* Generalized from CronManager to support pluggable phases (cron, dispatch,
|
|
5
|
+
* stall detection, etc.) in a single background loop.
|
|
6
|
+
*/
|
|
7
|
+
import { logger } from "./logger.js";
|
|
8
|
+
/** Default tick interval in milliseconds. */
|
|
9
|
+
const DEFAULT_TICK_INTERVAL_MS = 10_000;
|
|
10
|
+
/**
|
|
11
|
+
* Periodic reconciliation manager that runs ordered phases on a configurable interval.
|
|
12
|
+
*/
|
|
13
|
+
export class ReconciliationManager {
|
|
14
|
+
phases;
|
|
15
|
+
tickIntervalMs;
|
|
16
|
+
timer;
|
|
17
|
+
ticking = false;
|
|
18
|
+
tickPromise;
|
|
19
|
+
/**
|
|
20
|
+
* @param phases - Ordered list of phases to run on each tick
|
|
21
|
+
* @param tickIntervalMs - Override tick interval (default: GRACKLE_RECONCILIATION_TICK_MS env var or 10s)
|
|
22
|
+
*/
|
|
23
|
+
constructor(phases, tickIntervalMs) {
|
|
24
|
+
this.phases = phases;
|
|
25
|
+
if (tickIntervalMs !== undefined) {
|
|
26
|
+
this.tickIntervalMs = tickIntervalMs;
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
const envRaw = process.env.GRACKLE_RECONCILIATION_TICK_MS;
|
|
30
|
+
if (envRaw !== undefined && envRaw !== "") {
|
|
31
|
+
const parsed = parseInt(envRaw, 10);
|
|
32
|
+
if (Number.isFinite(parsed) && parsed > 0) {
|
|
33
|
+
this.tickIntervalMs = parsed;
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
logger.warn({ envValue: envRaw, default: DEFAULT_TICK_INTERVAL_MS }, "Invalid GRACKLE_RECONCILIATION_TICK_MS; falling back to default");
|
|
37
|
+
this.tickIntervalMs = DEFAULT_TICK_INTERVAL_MS;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
this.tickIntervalMs = DEFAULT_TICK_INTERVAL_MS;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/** Start the periodic ticker. */
|
|
46
|
+
start() {
|
|
47
|
+
if (this.timer) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
logger.info({ intervalMs: this.tickIntervalMs, phases: this.phases.map((p) => p.name) }, "ReconciliationManager started");
|
|
51
|
+
this.timer = setInterval(() => {
|
|
52
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
53
|
+
this.tryTick();
|
|
54
|
+
}, this.tickIntervalMs);
|
|
55
|
+
this.timer.unref();
|
|
56
|
+
}
|
|
57
|
+
/** Stop the ticker and await any in-flight tick. */
|
|
58
|
+
async stop() {
|
|
59
|
+
if (this.timer) {
|
|
60
|
+
clearInterval(this.timer);
|
|
61
|
+
this.timer = undefined;
|
|
62
|
+
}
|
|
63
|
+
if (this.tickPromise) {
|
|
64
|
+
await this.tickPromise;
|
|
65
|
+
}
|
|
66
|
+
logger.info("ReconciliationManager stopped");
|
|
67
|
+
}
|
|
68
|
+
/** Attempt a tick, skipping if a previous tick is still in-flight. */
|
|
69
|
+
async tryTick() {
|
|
70
|
+
if (this.ticking) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
this.ticking = true;
|
|
74
|
+
this.tickPromise = this.tick();
|
|
75
|
+
try {
|
|
76
|
+
await this.tickPromise;
|
|
77
|
+
}
|
|
78
|
+
catch (err) {
|
|
79
|
+
logger.error({ err }, "ReconciliationManager tick failed");
|
|
80
|
+
}
|
|
81
|
+
finally {
|
|
82
|
+
this.ticking = false;
|
|
83
|
+
this.tickPromise = undefined;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/** Execute one tick: run each phase sequentially, isolating errors. */
|
|
87
|
+
async tick() {
|
|
88
|
+
for (const phase of this.phases) {
|
|
89
|
+
try {
|
|
90
|
+
await phase.execute();
|
|
91
|
+
}
|
|
92
|
+
catch (err) {
|
|
93
|
+
logger.error({ err, phase: phase.name }, "Reconciliation phase '%s' failed", phase.name);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=reconciliation-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reconciliation-manager.js","sourceRoot":"","sources":["../src/reconciliation-manager.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@grackle-ai/core",
|
|
3
|
-
"version": "0.79.
|
|
3
|
+
"version": "0.79.1",
|
|
4
4
|
"description": "Core gRPC business logic for Grackle — RPC handlers, event system, streaming, session lifecycle",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -37,12 +37,12 @@
|
|
|
37
37
|
"ulid": "^2.3.0",
|
|
38
38
|
"uuid": "^11.0.0",
|
|
39
39
|
"ws": "^8.0.0",
|
|
40
|
-
"@grackle-ai/adapter-sdk": "0.79.
|
|
41
|
-
"@grackle-ai/
|
|
42
|
-
"@grackle-ai/
|
|
43
|
-
"@grackle-ai/knowledge": "0.79.
|
|
44
|
-
"@grackle-ai/
|
|
45
|
-
"@grackle-ai/prompt": "0.79.
|
|
40
|
+
"@grackle-ai/adapter-sdk": "0.79.1",
|
|
41
|
+
"@grackle-ai/auth": "0.79.1",
|
|
42
|
+
"@grackle-ai/common": "0.79.1",
|
|
43
|
+
"@grackle-ai/knowledge": "0.79.1",
|
|
44
|
+
"@grackle-ai/database": "0.79.1",
|
|
45
|
+
"@grackle-ai/prompt": "0.79.1"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
48
|
"@rushstack/heft": "1.2.7",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cron-manager.d.ts","sourceRoot":"","sources":["../src/cron-manager.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AACjF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAMvD,sEAAsE;AACtE,MAAM,WAAW,eAAe;IAC9B,gDAAgD;IAChD,eAAe,EAAE,MAAM,WAAW,EAAE,CAAC;IACrC,+EAA+E;IAC/E,eAAe,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5E,2CAA2C;IAC3C,UAAU,EAAE,CACV,EAAE,EAAE,MAAM,EACV,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EAAE,EACnB,aAAa,EAAE,MAAM,EACrB,YAAY,CAAC,EAAE,MAAM,EACrB,YAAY,CAAC,EAAE,OAAO,EACtB,gBAAgB,CAAC,EAAE,MAAM,KACtB,IAAI,CAAC;IACV,wCAAwC;IACxC,iBAAiB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAChE,yEAAyE;IACzE,gBAAgB,EAAE,CAChB,EAAE,EAAE,SAAS,EACb,IAAI,EAAE,OAAO,EACb,OAAO,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,aAAa,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,KACrE,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACjC,2BAA2B;IAC3B,IAAI,EAAE,CAAC,IAAI,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IACzE,4DAA4D;IAC5D,6BAA6B,EAAE,MAAM,cAAc,GAAG,SAAS,CAAC;IAChE,+BAA+B;IAC/B,UAAU,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAC;IACtF,0DAA0D;IAC1D,OAAO,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,GAAG,SAAS,CAAC;IAC7C,mEAAmE;IAEnE,kBAAkB,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IACrF,4CAA4C;IAC5C,sBAAsB,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,OAAO,CAAC;CAC5D;AAED;;GAEG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAkB;IACvC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,KAAK,CAA6C;IAC1D,OAAO,CAAC,OAAO,CAAkB;IACjC,OAAO,CAAC,WAAW,CAA4B;IAE/C;;;OAGG;gBACgB,IAAI,EAAE,eAAe,EAAE,eAAe,CAAC,EAAE,MAAM;IAKlE,iCAAiC;IAC1B,KAAK,IAAI,IAAI;IAepB,oDAAoD;IACvC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAWlC,sEAAsE;YACxD,OAAO;IAgBrB,2DAA2D;YAC7C,IAAI;IAWlB,mEAAmE;YACrD,YAAY;CAyH3B"}
|
package/dist/cron-manager.js
DELETED
|
@@ -1,167 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* CronManager — periodic ticker that fires due schedules.
|
|
3
|
-
*
|
|
4
|
-
* Runs as a background interval on the server, checking the schedule store
|
|
5
|
-
* for due entries on each tick and spawning tasks for them.
|
|
6
|
-
*/
|
|
7
|
-
import { v4 as uuidv4 } from "uuid";
|
|
8
|
-
import { logger } from "./logger.js";
|
|
9
|
-
import { computeNextRunAt } from "./schedule-expression.js";
|
|
10
|
-
import { ROOT_TASK_ID } from "@grackle-ai/common";
|
|
11
|
-
/** Default tick interval in milliseconds. */
|
|
12
|
-
const DEFAULT_CHECK_INTERVAL_MS = 10_000;
|
|
13
|
-
/**
|
|
14
|
-
* Periodic cron manager that checks for due schedules and fires them.
|
|
15
|
-
*/
|
|
16
|
-
export class CronManager {
|
|
17
|
-
deps;
|
|
18
|
-
checkIntervalMs;
|
|
19
|
-
timer;
|
|
20
|
-
ticking = false;
|
|
21
|
-
tickPromise;
|
|
22
|
-
/**
|
|
23
|
-
* @param deps - Injected dependencies
|
|
24
|
-
* @param checkIntervalMs - How often to check for due schedules (default 10s)
|
|
25
|
-
*/
|
|
26
|
-
constructor(deps, checkIntervalMs) {
|
|
27
|
-
this.deps = deps;
|
|
28
|
-
this.checkIntervalMs = checkIntervalMs ?? DEFAULT_CHECK_INTERVAL_MS;
|
|
29
|
-
}
|
|
30
|
-
/** Start the periodic ticker. */
|
|
31
|
-
start() {
|
|
32
|
-
if (this.timer) {
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
logger.info({ intervalMs: this.checkIntervalMs }, "CronManager started");
|
|
36
|
-
this.timer = setInterval(() => {
|
|
37
|
-
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
38
|
-
this.tryTick();
|
|
39
|
-
}, this.checkIntervalMs);
|
|
40
|
-
this.timer.unref();
|
|
41
|
-
}
|
|
42
|
-
/** Stop the ticker and await any in-flight tick. */
|
|
43
|
-
async stop() {
|
|
44
|
-
if (this.timer) {
|
|
45
|
-
clearInterval(this.timer);
|
|
46
|
-
this.timer = undefined;
|
|
47
|
-
}
|
|
48
|
-
if (this.tickPromise) {
|
|
49
|
-
await this.tickPromise;
|
|
50
|
-
}
|
|
51
|
-
logger.info("CronManager stopped");
|
|
52
|
-
}
|
|
53
|
-
/** Attempt a tick, skipping if a previous tick is still in-flight. */
|
|
54
|
-
async tryTick() {
|
|
55
|
-
if (this.ticking) {
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
58
|
-
this.ticking = true;
|
|
59
|
-
this.tickPromise = this.tick();
|
|
60
|
-
try {
|
|
61
|
-
await this.tickPromise;
|
|
62
|
-
}
|
|
63
|
-
catch (err) {
|
|
64
|
-
logger.error({ err }, "CronManager tick failed");
|
|
65
|
-
}
|
|
66
|
-
finally {
|
|
67
|
-
this.ticking = false;
|
|
68
|
-
this.tickPromise = undefined;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
/** Execute one tick: query due schedules and fire each. */
|
|
72
|
-
async tick() {
|
|
73
|
-
const due = this.deps.getDueSchedules();
|
|
74
|
-
if (due.length === 0) {
|
|
75
|
-
return;
|
|
76
|
-
}
|
|
77
|
-
logger.debug({ count: due.length }, "CronManager tick: due schedules");
|
|
78
|
-
for (const schedule of due) {
|
|
79
|
-
await this.fireSchedule(schedule);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
/** Fire a single schedule: create task, start session, advance. */
|
|
83
|
-
async fireSchedule(schedule) {
|
|
84
|
-
const now = new Date().toISOString();
|
|
85
|
-
let nextRunAt;
|
|
86
|
-
try {
|
|
87
|
-
// Anchor to the schedule's lastRunAt (not current time) to prevent drift
|
|
88
|
-
nextRunAt = computeNextRunAt(schedule.scheduleExpression, schedule.lastRunAt ?? undefined);
|
|
89
|
-
}
|
|
90
|
-
catch (err) {
|
|
91
|
-
logger.error({ scheduleId: schedule.id, scheduleExpression: schedule.scheduleExpression, err }, "CronManager: failed to compute nextRunAt; disabling schedule");
|
|
92
|
-
// Disable the schedule to prevent error loop on every tick
|
|
93
|
-
this.deps.setScheduleEnabled(schedule.id, false, null);
|
|
94
|
-
return;
|
|
95
|
-
}
|
|
96
|
-
try {
|
|
97
|
-
// Resolve environment — check connectivity before creating tasks to avoid orphan tasks
|
|
98
|
-
let environmentId;
|
|
99
|
-
if (schedule.environmentId) {
|
|
100
|
-
// Explicit environment: verify it's connected before creating a task
|
|
101
|
-
if (!this.deps.isEnvironmentConnected(schedule.environmentId)) {
|
|
102
|
-
logger.warn({ scheduleId: schedule.id, environmentId: schedule.environmentId }, "Schedule fire skipped: specified environment not connected");
|
|
103
|
-
this.deps.advanceSchedule(schedule.id, now, nextRunAt);
|
|
104
|
-
return;
|
|
105
|
-
}
|
|
106
|
-
environmentId = schedule.environmentId;
|
|
107
|
-
}
|
|
108
|
-
else {
|
|
109
|
-
// Auto-select first connected environment
|
|
110
|
-
const env = this.deps.findFirstConnectedEnvironment();
|
|
111
|
-
if (!env) {
|
|
112
|
-
logger.warn({ scheduleId: schedule.id }, "Schedule fire skipped: no connected environment");
|
|
113
|
-
this.deps.advanceSchedule(schedule.id, now, nextRunAt);
|
|
114
|
-
return;
|
|
115
|
-
}
|
|
116
|
-
environmentId = env.id;
|
|
117
|
-
}
|
|
118
|
-
// Validate persona exists
|
|
119
|
-
const persona = this.deps.getPersona(schedule.personaId);
|
|
120
|
-
if (!persona) {
|
|
121
|
-
logger.warn({ scheduleId: schedule.id, personaId: schedule.personaId }, "Schedule fire skipped: persona not found");
|
|
122
|
-
this.deps.advanceSchedule(schedule.id, now, nextRunAt);
|
|
123
|
-
return;
|
|
124
|
-
}
|
|
125
|
-
// Create task
|
|
126
|
-
const taskId = uuidv4();
|
|
127
|
-
const taskTitle = `${schedule.title} @ ${now}`;
|
|
128
|
-
const parentTaskId = schedule.parentTaskId || ROOT_TASK_ID;
|
|
129
|
-
this.deps.createTask(taskId, schedule.workspaceId || undefined, taskTitle, schedule.description, [], // no dependencies
|
|
130
|
-
"", // no workspace slug
|
|
131
|
-
parentTaskId, false, // canDecompose
|
|
132
|
-
schedule.personaId);
|
|
133
|
-
this.deps.setTaskScheduleId(taskId, schedule.id);
|
|
134
|
-
// Fetch the created task for startTaskSession
|
|
135
|
-
const task = this.deps.getTask(taskId);
|
|
136
|
-
if (!task) {
|
|
137
|
-
logger.error({ scheduleId: schedule.id, taskId }, "Schedule fire failed: created task not found");
|
|
138
|
-
this.deps.advanceSchedule(schedule.id, now, nextRunAt);
|
|
139
|
-
return;
|
|
140
|
-
}
|
|
141
|
-
// Start the task session
|
|
142
|
-
const error = await this.deps.startTaskSession(undefined, task, {
|
|
143
|
-
environmentId,
|
|
144
|
-
personaId: schedule.personaId,
|
|
145
|
-
});
|
|
146
|
-
// Advance schedule regardless of session start outcome
|
|
147
|
-
this.deps.advanceSchedule(schedule.id, now, nextRunAt);
|
|
148
|
-
if (error) {
|
|
149
|
-
logger.warn({ scheduleId: schedule.id, taskId, error }, "Schedule fire: task created but session start failed");
|
|
150
|
-
return;
|
|
151
|
-
}
|
|
152
|
-
// Emit event only on successful fire
|
|
153
|
-
this.deps.emit("schedule.fired", {
|
|
154
|
-
scheduleId: schedule.id,
|
|
155
|
-
taskId,
|
|
156
|
-
firedAt: now,
|
|
157
|
-
});
|
|
158
|
-
logger.info({ scheduleId: schedule.id, taskId, title: schedule.title }, "Schedule fired");
|
|
159
|
-
}
|
|
160
|
-
catch (err) {
|
|
161
|
-
logger.error({ scheduleId: schedule.id, err }, "Schedule fire failed with exception");
|
|
162
|
-
// Still advance to prevent retry storms
|
|
163
|
-
this.deps.advanceSchedule(schedule.id, now, nextRunAt);
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
//# sourceMappingURL=cron-manager.js.map
|
package/dist/cron-manager.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cron-manager.js","sourceRoot":"","sources":["../src/cron-manager.ts"],"names":[],"mappings":"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"}
|