mirror of
https://github.com/getpaseo/paseo.git
synced 2026-10-14 13:22:37 +00:00
fix(schedule): keep firing after a run that could not be recorded (#6334)
* fix(schedule): keep firing after a run that could not be recorded A schedule whose running-run write failed stayed marked as running in memory, so every later tick skipped it and run-once reported it as already running until the daemon restarted. The running mark is now cleared whenever the run ends, including when it could not be recorded, and the next tick retries the due run. * test(schedule): skip the unwritable-directory test as root --------- Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
|
||||
import { chmod, mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
|
||||
import { join } from "node:path";
|
||||
import { tmpdir } from "node:os";
|
||||
import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
|
||||
@@ -2867,6 +2867,44 @@ describe("ScheduleService", () => {
|
||||
expect(inspected.runs[0]?.error).toBe("network blip");
|
||||
});
|
||||
|
||||
// chmod cannot make a directory unwritable on Windows or for root.
|
||||
test.skipIf(process.platform === "win32" || process.getuid?.() === 0)(
|
||||
"fires again after a tick whose run could not be recorded",
|
||||
async () => {
|
||||
const service = createScheduleService({
|
||||
paseoHome: tempDir,
|
||||
logger: createTestLogger(),
|
||||
agentManager: new AgentManager({ logger: createTestLogger() }),
|
||||
agentStorage,
|
||||
providerSnapshotManager: NO_UNATTENDED_SCHEDULE_POLICY,
|
||||
now: () => now,
|
||||
runner: async () => ({ agentId: null, output: "ran" }),
|
||||
});
|
||||
|
||||
const created = await service.create({
|
||||
prompt: "ping target",
|
||||
cadence: { type: "every", everyMs: 60_000 },
|
||||
target: { type: "agent", agentId: "88888888-8888-4888-8888-888888888888" },
|
||||
});
|
||||
|
||||
const schedulesDir = join(tempDir, "schedules");
|
||||
now = new Date("2026-01-01T00:01:00.000Z");
|
||||
await chmod(schedulesDir, 0o555);
|
||||
try {
|
||||
await expect(service.tick()).rejects.toThrow();
|
||||
} finally {
|
||||
await chmod(schedulesDir, 0o755);
|
||||
}
|
||||
|
||||
await service.tick();
|
||||
|
||||
const inspected = await service.inspect(created.id);
|
||||
expect(inspected.runs).toHaveLength(1);
|
||||
expect(inspected.runs[0]?.status).toBe("succeeded");
|
||||
expect(inspected.nextRunAt).toBe("2026-01-01T00:02:00.000Z");
|
||||
},
|
||||
);
|
||||
|
||||
test("completes the schedule when a scheduled run targets an archived agent", async () => {
|
||||
const service = createScheduleService({
|
||||
paseoHome: tempDir,
|
||||
|
||||
@@ -694,6 +694,7 @@ export class ScheduleService {
|
||||
): Promise<void> {
|
||||
const manual = options?.manual === true;
|
||||
this.runningScheduleIds.add(schedule.id);
|
||||
try {
|
||||
const runId = randomUUID();
|
||||
const runningRun: ScheduleRun = {
|
||||
id: runId,
|
||||
@@ -730,6 +731,7 @@ export class ScheduleService {
|
||||
targetGone: error instanceof ScheduleTargetGoneError,
|
||||
manual,
|
||||
});
|
||||
}
|
||||
} finally {
|
||||
this.runningScheduleIds.delete(schedule.id);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user