Skip to content

feat(scans): allow one in-flight scan per branch, not per project - #9

Merged
haksungjang merged 1 commit into
mainfrom
feat/concurrent-scans-per-branch
Aug 4, 2026
Merged

feat(scans): allow one in-flight scan per branch, not per project#9
haksungjang merged 1 commit into
mainfrom
feat/concurrent-scans-per-branch

Conversation

@haksungjang

Copy link
Copy Markdown
Contributor

ix_scans_project_active enforced at most one queued/running scan per project. Once branches became a first-class axis (#6, #7, #8), that stopped matching the model: pushing to main and release/1.x at the same time made one CI job wait on the other's scan, or take a 409 it could do nothing about. The two branches write disjoint snapshots, so nothing about the data required serializing them.

Migration 0047 rebuilds the index on (project_id, ref) with NULLS NOT DISTINCT. That second half is the point: ref is NULL for ad-hoc scans, which is most rows, and under the default NULLS DISTINCT a plain (project_id, ref) unique index would stop constraining them at all — every manual re-trigger would queue another scan and the stability guard would become nothing for the common case. With NULLS NOT DISTINCT (PostgreSQL 15+; we pin 17) all ref-less rows of a project still collide, so ad-hoc behaviour is unchanged and only named branches gain concurrency.

The 409 detail now names the busy branch, since "a scan is already running for this project" would send a caller looking for a conflict on a branch they never touched.

The Scan button was greying out on any active scan, which would have hidden the whole change in the UI. It triggers an ad-hoc run, so only another ad-hoc scan can conflict with it — it now gates on that, and the in-progress chip stays visible either way. This needed ref on the overview's recent-scans summary.

The per-team concurrency cap docstring claimed the old index guaranteed "at most ONE active scan per project"; corrected. The bound it derives comes from the per-user rate limit and is unchanged.

ix_scans_project_active serialized every scan of a project, so pushing to
main and release/1.x at once made one CI job wait on the other's scan or
take a 409 it could do nothing about. The branches write disjoint
snapshots; nothing about the data required that.

Migration 0047 rebuilds the index on (project_id, ref) NULLS NOT DISTINCT.
Without NULLS NOT DISTINCT the ref-less ad-hoc scans that make up most rows
would stop colliding entirely, turning the guard into nothing for the
common case; with it they keep exactly today's behaviour.

The Scan button now greys out only while another ad-hoc scan is in flight,
since that is the only kind it can conflict with. That needed ref on the
overview's recent-scans summary.
@haksungjang
haksungjang merged commit 83b7f9b into main Aug 4, 2026
24 checks passed
@haksungjang
haksungjang deleted the feat/concurrent-scans-per-branch branch August 4, 2026 09:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant