Fix routine run assignment wakeups

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
dotta
2026-03-20 08:58:24 -05:00
parent 2d8c8abbfb
commit 5b1e1239fd
4 changed files with 37 additions and 7 deletions

View File

@@ -115,7 +115,20 @@ describe("routine service live-execution coalescing", () => {
} }
}); });
async function seedFixture() { async function seedFixture(opts?: {
wakeup?: (
agentId: string,
wakeupOpts: {
source?: string;
triggerDetail?: string;
reason?: string | null;
payload?: Record<string, unknown> | null;
requestedByActorType?: "user" | "agent" | "system";
requestedByActorId?: string | null;
contextSnapshot?: Record<string, unknown>;
},
) => Promise<unknown>;
}) {
const companyId = randomUUID(); const companyId = randomUUID();
const agentId = randomUUID(); const agentId = randomUUID();
const projectId = randomUUID(); const projectId = randomUUID();
@@ -161,9 +174,9 @@ describe("routine service live-execution coalescing", () => {
const svc = routineService(db, { const svc = routineService(db, {
heartbeat: { heartbeat: {
wakeup: async (agentId, opts) => { wakeup: async (wakeupAgentId, wakeupOpts) => {
wakeups.push({ agentId, opts }); wakeups.push({ agentId: wakeupAgentId, opts: wakeupOpts });
return null; return opts?.wakeup ? opts.wakeup(wakeupAgentId, wakeupOpts) : null;
}, },
}, },
}); });
@@ -258,6 +271,22 @@ describe("routine service live-execution coalescing", () => {
]); ]);
}); });
it("waits for the assignee wakeup to be queued before returning the routine run", async () => {
let wakeupResolved = false;
const { routine, svc } = await seedFixture({
wakeup: async () => {
await new Promise((resolve) => setTimeout(resolve, 10));
wakeupResolved = true;
return null;
},
});
const run = await svc.runRoutine(routine.id, { source: "manual" });
expect(run.status).toBe("issue_created");
expect(wakeupResolved).toBe(true);
});
it("coalesces only when the existing routine issue has a live execution run", async () => { it("coalesces only when the existing routine issue has a live execution run", async () => {
const { agentId, companyId, issueSvc, routine, svc } = await seedFixture(); const { agentId, companyId, issueSvc, routine, svc } = await seedFixture();
const previousRunId = randomUUID(); const previousRunId = randomUUID();

View File

@@ -782,7 +782,7 @@ export function issueRoutes(db: Db, storage: StorageService) {
details: { title: issue.title, identifier: issue.identifier }, details: { title: issue.title, identifier: issue.identifier },
}); });
queueIssueAssignmentWakeup({ void queueIssueAssignmentWakeup({
heartbeat, heartbeat,
issue, issue,
reason: "issue_assigned", reason: "issue_assigned",

View File

@@ -29,7 +29,7 @@ export function queueIssueAssignmentWakeup(input: {
}) { }) {
if (!input.issue.assigneeAgentId || input.issue.status === "backlog") return; if (!input.issue.assigneeAgentId || input.issue.status === "backlog") return;
void input.heartbeat return input.heartbeat
.wakeup(input.issue.assigneeAgentId, { .wakeup(input.issue.assigneeAgentId, {
source: "assignment", source: "assignment",
triggerDetail: "system", triggerDetail: "system",

View File

@@ -619,7 +619,8 @@ export function routineService(db: Db, deps: { heartbeat?: IssueAssignmentWakeup
status: "issue_created", status: "issue_created",
linkedIssueId: createdIssue.id, linkedIssueId: createdIssue.id,
}); });
queueIssueAssignmentWakeup({ // Ensure the wake request is durably queued before reporting the routine run as created.
await queueIssueAssignmentWakeup({
heartbeat, heartbeat,
issue: createdIssue, issue: createdIssue,
reason: "issue_assigned", reason: "issue_assigned",