| 1575 | 1575 | | labels: String, |
| 1576 | 1576 | | queued_at: Option<String>, |
| 1577 | 1577 | | repo: String, |
| 1578 | + | repo_id: String, |
| 1578 | 1579 | | } |
| 1579 | 1580 | | let waiting = self |
| 1580 | 1581 | | .db |
| 1581 | 1582 | | .prepare( |
| 1582 | | − | "SELECT jobs.id, jobs.name, jobs.run_id, jobs.labels, jobs.queued_at, runs.repo FROM jobs JOIN runs ON runs.id = jobs.run_id |
| 1583 | + | "SELECT jobs.id, jobs.name, jobs.run_id, jobs.labels, jobs.queued_at, runs.repo, jobs.repo_id FROM jobs JOIN runs ON runs.id = jobs.run_id |
| 1583 | 1584 | | WHERE jobs.status = 'queued' AND jobs.labels IS NOT NULL AND lower(jobs.namespace) = ? AND jobs.queued_at < ? |
| 1584 | 1585 | | ORDER BY jobs.rowid LIMIT 20", |
| 1585 | 1586 | | ) |
| ⋯ |
| 1592 | 1593 | | } |
| 1593 | 1594 | | let groups = self.group_rows(&workspace).await?; |
| 1594 | 1595 | | let online: Vec<RunnerRow> = self.runner_rows(&workspace).await?.into_iter().filter(|r| r.online(at)).collect(); |
| 1596 | + | // A repository's visibility is asked only when a host-mode runner |
| 1597 | + | // is online, since only those pass over a public repository's jobs. |
| 1598 | + | let any_host = online.iter().any(|runner| runner.isolation.as_deref() == Some("host")); |
| 1599 | + | let mut looked = Looked::default(); |
| 1595 | 1600 | | for job in waiting { |
| 1596 | 1601 | | let wanted = Wanted::from_stored(&serde_json::from_str::<Vec<String>>(&job.labels).unwrap_or_default()); |
| 1602 | + | let visibility = if any_host { self.visibility_once(&mut looked, &job.repo_id).await } else { None }; |
| 1597 | 1603 | | let served = online.iter().any(|runner| { |
| 1598 | 1604 | | let group = runner.group_id.as_ref().and_then(|id| groups.iter().find(|g| &g.id == id)); |
| 1599 | 1605 | | wanted.matches(&runner.labels(), group.map(|g| g.name.as_str())) |
| 1606 | + | && model::isolation_allows(runner.isolation.as_deref(), visibility.as_deref()) |
| 1600 | 1607 | | }); |
| 1601 | 1608 | | if !served { |
| 1602 | 1609 | | out.push(StuckJob { |