Skip to content

Commit eebbeb5

Browse files
committed
Discrimination between "outdated" and "extraneous" prebuilds, hardening reconciliation
Signed-off-by: Danny Kopping <danny@coder.com>
1 parent fdabb8c commit eebbeb5

File tree

3 files changed

+212
-124
lines changed

3 files changed

+212
-124
lines changed

coderd/database/queries.sql.go

+69-59
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/queries/prebuilds.sql

+67-59
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,75 @@
11
-- name: GetTemplatePrebuildState :many
22
WITH
3-
-- All prebuilds currently running
4-
running_prebuilds AS (SELECT p.template_id,
5-
b.template_version_id,
6-
COUNT(*) AS count,
7-
STRING_AGG(p.id::text, ',') AS ids
8-
FROM workspace_prebuilds p
9-
INNER JOIN workspace_latest_build b ON b.workspace_id = p.id
10-
INNER JOIN provisioner_jobs pj ON b.job_id = pj.id
11-
INNER JOIN templates t ON p.template_id = t.id
12-
WHERE (b.transition = 'start'::workspace_transition
13-
-- if a deletion job fails, the workspace will still be running
14-
OR pj.job_status IN ('failed'::provisioner_job_status, 'canceled'::provisioner_job_status,
15-
'unknown'::provisioner_job_status))
16-
GROUP BY p.template_id, b.template_version_id),
17-
-- All templates which have been configured for prebuilds (any version)
18-
templates_with_prebuilds AS (SELECT t.id AS template_id,
19-
tv.id AS template_version_id,
20-
tv.id = t.active_version_id AS using_active_version,
21-
tvpp.desired_instances,
22-
t.deleted,
23-
t.deprecated != '' AS deprecated
24-
FROM templates t
25-
INNER JOIN template_versions tv ON tv.template_id = t.id
26-
INNER JOIN template_version_presets tvp ON tvp.template_version_id = tv.id
27-
INNER JOIN template_version_preset_prebuilds tvpp ON tvpp.preset_id = tvp.id
28-
WHERE t.id = @template_id::uuid
29-
GROUP BY t.id, tv.id, tvpp.id),
30-
-- Jobs relating to prebuilds current in-flight
31-
prebuilds_in_progress AS (SELECT wpb.template_version_id, wpb.transition, COUNT(wpb.transition) AS count
32-
FROM workspace_latest_build wlb
33-
INNER JOIN provisioner_jobs pj ON wlb.job_id = pj.id
34-
INNER JOIN workspace_prebuild_builds wpb ON wpb.id = wlb.id
35-
WHERE pj.job_status NOT IN
36-
('succeeded'::provisioner_job_status, 'canceled'::provisioner_job_status,
37-
'failed'::provisioner_job_status)
38-
GROUP BY wpb.template_version_id, wpb.transition)
3+
-- All prebuilds currently running
4+
running_prebuilds AS (SELECT p.template_id,
5+
b.template_version_id,
6+
COUNT(*) AS count,
7+
STRING_AGG(p.id::text, ',') AS ids
8+
FROM workspace_prebuilds p
9+
INNER JOIN workspace_latest_build b ON b.workspace_id = p.id
10+
INNER JOIN provisioner_jobs pj ON b.job_id = pj.id
11+
INNER JOIN templates t ON p.template_id = t.id
12+
WHERE (b.transition = 'start'::workspace_transition
13+
-- if a deletion job fails, the workspace will still be running
14+
OR pj.job_status IN ('failed'::provisioner_job_status, 'canceled'::provisioner_job_status,
15+
'unknown'::provisioner_job_status))
16+
GROUP BY p.template_id, b.template_version_id),
17+
-- All templates which have been configured for prebuilds (any version)
18+
templates_with_prebuilds AS (SELECT t.id AS template_id,
19+
tv.id AS template_version_id,
20+
tv.id = t.active_version_id AS using_active_version,
21+
tvpp.desired_instances,
22+
t.deleted,
23+
t.deprecated != '' AS deprecated
24+
FROM templates t
25+
INNER JOIN template_versions tv ON tv.template_id = t.id
26+
INNER JOIN template_version_presets tvp ON tvp.template_version_id = tv.id
27+
INNER JOIN template_version_preset_prebuilds tvpp ON tvpp.preset_id = tvp.id
28+
WHERE t.id = @template_id::uuid
29+
GROUP BY t.id, tv.id, tvpp.id),
30+
-- Jobs relating to prebuilds current in-flight
31+
prebuilds_in_progress AS (SELECT wpb.template_version_id, wpb.transition, COUNT(wpb.transition) AS count
32+
FROM workspace_latest_build wlb
33+
INNER JOIN provisioner_jobs pj ON wlb.job_id = pj.id
34+
INNER JOIN workspace_prebuild_builds wpb ON wpb.id = wlb.id
35+
WHERE pj.job_status NOT IN
36+
('succeeded'::provisioner_job_status, 'canceled'::provisioner_job_status,
37+
'failed'::provisioner_job_status)
38+
GROUP BY wpb.template_version_id, wpb.transition)
3939
SELECT t.template_id,
40-
t.template_version_id,
41-
t.using_active_version AS is_active,
42-
COALESCE(MAX(CASE WHEN p.template_version_id = t.template_version_id THEN p.ids END),
43-
'')::text AS running_prebuild_ids,
44-
COALESCE(MAX(CASE WHEN t.using_active_version THEN p.count ELSE 0 END),
45-
0)::int AS actual, -- running prebuilds for active version
46-
COALESCE(MAX(CASE WHEN t.using_active_version THEN t.desired_instances ELSE 0 END),
47-
0)::int AS desired, -- we only care about the active version's desired instances
48-
COALESCE(MAX(CASE
49-
WHEN p.template_version_id = t.template_version_id AND t.using_active_version = false
50-
THEN p.count END),
51-
0)::int AS extraneous, -- running prebuilds for inactive version
52-
COALESCE(MAX(CASE WHEN pip.transition = 'start'::workspace_transition THEN pip.count ELSE 0 END),
53-
0)::int AS starting,
54-
COALESCE(MAX(CASE WHEN pip.transition = 'stop'::workspace_transition THEN pip.count ELSE 0 END),
55-
0)::int AS stopping, -- not strictly needed, since prebuilds should never be left if a "stopped" state, but useful to know
56-
COALESCE(MAX(CASE WHEN pip.transition = 'delete'::workspace_transition THEN pip.count ELSE 0 END),
57-
0)::int AS deleting,
58-
t.deleted AS template_deleted,
59-
t.deprecated AS template_deprecated
40+
t.template_version_id,
41+
t.using_active_version AS is_active,
42+
MAX(CASE
43+
WHEN p.template_version_id = t.template_version_id THEN p.ids
44+
ELSE '' END)::text AS running_prebuild_ids,
45+
COALESCE(MAX(CASE WHEN t.using_active_version THEN p.count ELSE 0 END),
46+
0)::int AS actual, -- running prebuilds for active version
47+
MAX(CASE WHEN t.using_active_version THEN t.desired_instances ELSE 0 END)::int AS desired, -- we only care about the active version's desired instances
48+
COALESCE(MAX(CASE
49+
WHEN p.template_version_id = t.template_version_id AND t.using_active_version = false
50+
THEN p.count
51+
ELSE 0 END),
52+
0)::int AS outdated, -- running prebuilds for inactive version
53+
COALESCE(GREATEST(
54+
(MAX(CASE WHEN t.using_active_version THEN p.count ELSE 0 END)::int
55+
- MAX(CASE WHEN t.using_active_version THEN t.desired_instances ELSE 0 END)),
56+
0),
57+
0) ::int AS extraneous, -- extra running prebuilds for active version
58+
COALESCE(MAX(CASE WHEN pip.transition = 'start'::workspace_transition THEN pip.count ELSE 0 END),
59+
0)::int AS starting,
60+
COALESCE(MAX(CASE
61+
WHEN pip.transition = 'stop'::workspace_transition THEN pip.count
62+
ELSE 0 END),
63+
0)::int AS stopping, -- not strictly needed, since prebuilds should never be left if a "stopped" state, but useful to know
64+
COALESCE(MAX(CASE WHEN pip.transition = 'delete'::workspace_transition THEN pip.count ELSE 0 END),
65+
0)::int AS deleting,
66+
t.deleted AS template_deleted,
67+
t.deprecated AS template_deprecated
6068
FROM templates_with_prebuilds t
61-
LEFT JOIN running_prebuilds p ON p.template_version_id = t.template_version_id
62-
LEFT JOIN prebuilds_in_progress pip ON pip.template_version_id = t.template_version_id
69+
LEFT JOIN running_prebuilds p ON p.template_version_id = t.template_version_id
70+
LEFT JOIN prebuilds_in_progress pip ON pip.template_version_id = t.template_version_id
6371
GROUP BY t.using_active_version, t.template_id, t.template_version_id, p.count, p.ids,
64-
p.template_version_id, t.deleted, t.deprecated;
72+
p.template_version_id, t.deleted, t.deprecated;
6573

6674
-- name: ClaimPrebuild :one
6775
UPDATE workspaces w

0 commit comments

Comments
 (0)