Commit

Queued issues are never dropped on the way to an agent, and a start that fails says why

ready_issues took an issue off the queue, then looked its repository up as whoever queued it; when that lookup failed the issue was lost: no pull request, no comment, no retry. Planned issues opened with 'assign g1t' sat untouched. The address now comes from path_by_id (the runner checks permissions when it starts), and an issue that cannot be handed over goes back on the queue. The runner logs every start it could not make, and says on the issue when one is refused for good.

syntaqxcommitted Parent24ac7a4Browse files
2 files+24−240/2 viewed
+6−3
18961896 if (started.ok) continue;
18971897 // Waiting for a slot: `run` put it back in the queue itself.
18981898 if (isWaiting(started.error.message)) continue;
1899− // The workspace's plan refused it: said on the issue, once, rather
1900− // than tried again every few minutes.
1901− if (started.error.code === "payment_required") {
1899+ const where = `${issue.repo.namespace}/${issue.repo.name}#${issue.number}`;
1900+ console.error(`startReady: ${where} not started (${started.error.code}): ${started.error.message}`);
1901+ // Refused for good (the plan, or who queued it may not run agents
1902+ // here): said on the issue, once, rather than tried again every few
1903+ // minutes with nothing to show for it.
1904+ if (started.error.code === "payment_required" || started.error.code === "forbidden") {
19021905 await agentsClient(this.env.WORK)
19031906 .agentComment(issue.repo, issue.number, `I could not start on this: ${started.error.message}`)
19041907 .catch(() => false);
+18−21
1212
1313 use g1t_contracts::access::Capability;
1414 use g1t_contracts::events::IssueEvent;
15−use g1t_contracts::repos::{GetByIdArgs, Repo, RepoPath};
15+use g1t_contracts::repos::{PathByIdArgs, Repo, RepoPath};
1616 use g1t_contracts::time::rfc3339;
1717 use g1t_contracts::work::*;
1818 use g1t_contracts::{FailureCode, Outcome, User, new_id};
620620 continue;
621621 }
622622 *left -= 1;
623− // Whoever queued it could see the repository then; where it is
624− // now is asked as them.
625− let repo: Outcome<Repo> = g1t_kit::call(
626− &self.repos,
627− "get_by_id",
628− &GetByIdArgs {
629− id: row.repo_id.clone(),
630− viewer: Some(actor.clone()),
631− },
632− )
633− .await?;
634− if let Outcome::Ok(repo) = repo {
635− ready.push(ReadyIssue {
636− repo: RepoPath {
637− namespace: repo.namespace,
638− name: repo.name,
639− },
640− number: row.number,
641− actor,
642− });
623+ // Where the repository is now. Who may run agents there is the
624+ // runner's question when it starts the issue, asked as whoever
625+ // queued it; this only needs the address.
626+ let path: Option<RepoPath> =
627+ g1t_kit::call(&self.repos, "path_by_id", &PathByIdArgs { id: row.repo_id.clone() }).await?;
628+ match path {
629+ Some(repo) => ready.push(ReadyIssue { repo, number: row.number, actor }),
630+ None => {
631+ // Taken but not handed over: put it back, so it is not
632+ // lost with nothing said.
633+ worker::console_error!("ready_issues: no path for {}; issue #{} stays queued", row.repo_id, row.number);
634+ self.db
635+ .prepare("UPDATE issues SET queued_by = ? WHERE repo_id = ? AND number = ?")
636+ .bind(&[row.queued_by.as_str().into(), row.repo_id.as_str().into(), row.number.into()])?
637+ .run()
638+ .await?;
639+ }
643640 }
644641 }
645642 Ok(ready)