Skip to content

feat: implement reconciliation loop #17261

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 158 commits into from
Apr 17, 2025
Merged
Show file tree
Hide file tree
Changes from 137 commits
Commits
Show all changes
158 commits
Select commit Hold shift + click to select a range
300e80f
add prebuilds system user database changes and associated changes
SasSwart Mar 12, 2025
b788237
optionally prevent system users from counting to user count
dannykopping Mar 13, 2025
8122595
appease the linter
dannykopping Mar 13, 2025
bfb7c28
add unit test for system user behaviour
dannykopping Mar 13, 2025
6639167
reverting RBAC changes; not relevant here
dannykopping Mar 13, 2025
769ae1d
removing unnecessary changes
dannykopping Mar 13, 2025
e7e9c27
exclude system user db tests from non-linux OSs
dannykopping Mar 13, 2025
3936047
Rename prebuild system user reference
SasSwart Mar 17, 2025
8bdcafb
ensure that users.IsSystem is not nullable
SasSwart Mar 17, 2025
412d198
feat: add migrations and queries to support prebuilds
SasSwart Mar 12, 2025
51773ec
Simplify workspace_latest_build view
dannykopping Mar 14, 2025
23773c2
Revert test change
dannykopping Mar 17, 2025
bc3ff44
make gen
dannykopping Mar 17, 2025
7ff747e
mark prebuilds as such and set their preset ids
SasSwart Mar 17, 2025
baa3076
refactor: add comments to SQL queries
evgeniy-scherbina Mar 19, 2025
ed14fb3
test: added get-presets-backoff test
evgeniy-scherbina Mar 20, 2025
3cc74fb
refactor: add comment to SQL query
evgeniy-scherbina Mar 20, 2025
fc32154
refactor: add comments + improve tests
evgeniy-scherbina Mar 21, 2025
d7b4ec4
fix: bug in SQL
evgeniy-scherbina Mar 21, 2025
e8b53f7
test: minor changes to the test
evgeniy-scherbina Mar 21, 2025
9df6554
refactor: remove job_status from SQL query
evgeniy-scherbina Mar 21, 2025
ccc309e
refactor: embed preset_prebuilds table into presets table
evgeniy-scherbina Mar 21, 2025
ee1f16a
refactor: rename sql table
evgeniy-scherbina Mar 21, 2025
d040ddd
refactor: remove unnecessary JOIN
evgeniy-scherbina Mar 23, 2025
83a6722
refactor: remove unnecessary JOIN
evgeniy-scherbina Mar 23, 2025
cd70710
refactor: use INNER JOIN for consistency
evgeniy-scherbina Mar 23, 2025
97cc4ff
refactor: simplify GetPresetsBackoff SQL Query
evgeniy-scherbina Mar 24, 2025
4d59039
Revert "refactor: simplify GetPresetsBackoff SQL Query"
evgeniy-scherbina Mar 24, 2025
205d6af
refactor: improve GetPresetsBackoff query
evgeniy-scherbina Mar 24, 2025
e489e1b
Merge remote-tracking branch 'origin/main' into prebuilds-db
evgeniy-scherbina Mar 25, 2025
1b29686
Merge remote-tracking branch 'origin/main' into prebuilds-db
evgeniy-scherbina Mar 25, 2025
20470e4
fix: bump migration numbers
evgeniy-scherbina Mar 25, 2025
7b9c8ce
test: remove deprecated test
evgeniy-scherbina Mar 25, 2025
e189a0b
fix: fix linter
evgeniy-scherbina Mar 25, 2025
692c0e5
fix: fix 000310_prebuilds.down migration
evgeniy-scherbina Mar 25, 2025
f747db0
fix: fix fixture migration
evgeniy-scherbina Mar 25, 2025
3166a42
fix: fix get-presets-backoff test
evgeniy-scherbina Mar 25, 2025
aa6b490
fix: fix linter
evgeniy-scherbina Mar 25, 2025
bc4e7d2
fix: fix linter
evgeniy-scherbina Mar 25, 2025
f167b92
correctly select for the latest built with a preset in latest_prebuil…
SasSwart Mar 26, 2025
8fd34ab
Merge remote-tracking branch 'origin/main' into prebuilds-db
SasSwart Mar 26, 2025
7a8ec49
Properly label and filter metrics for prebuilds
SasSwart Mar 26, 2025
a64d661
test: fix db tests
evgeniy-scherbina Mar 27, 2025
c787cd2
test: added tests for workspaces with multiple agents
evgeniy-scherbina Mar 27, 2025
bd38603
refactor: avoid code duplication
evgeniy-scherbina Mar 27, 2025
097f9c3
clarify query clause
SasSwart Mar 27, 2025
4cfdd6f
tidy up dbauthz_test.go
SasSwart Mar 27, 2025
4a34d52
refactor: remove * usage from prebuilds.sql queries
evgeniy-scherbina Mar 27, 2025
8d9cd45
refactor: remove * usage from prebuilds views
evgeniy-scherbina Mar 27, 2025
f870d7e
refactor: join wlb with pj
evgeniy-scherbina Mar 27, 2025
18ad931
refactor: Rename SQL query
evgeniy-scherbina Mar 27, 2025
4667171
Added comments for SQL query
evgeniy-scherbina Mar 27, 2025
a26c094
refactor: fix down migration
evgeniy-scherbina Mar 27, 2025
6ed4121
Merge remote-tracking branch 'origin/main' into prebuilds-db
SasSwart Mar 28, 2025
2312f41
renumber migrations
SasSwart Mar 28, 2025
8da7f47
Merge remote-tracking branch 'origin/prebuilds-db' into 16930
SasSwart Mar 28, 2025
5150a5c
refactor: clarify comment for SQL query
evgeniy-scherbina Mar 28, 2025
bff34ea
refactor: fix indentations
evgeniy-scherbina Mar 28, 2025
ef462b6
refactor: rename helper func in test package
evgeniy-scherbina Mar 28, 2025
dc45165
refactor: database level tests
evgeniy-scherbina Mar 28, 2025
9c8a352
refactor: database level tests
evgeniy-scherbina Mar 28, 2025
eb80919
refactor: helper funcs in db-level tests
evgeniy-scherbina Mar 28, 2025
0b2bbee
refactor: minor improvement in SQL query
evgeniy-scherbina Mar 28, 2025
3a97bf6
refactor: rename SQL queries
evgeniy-scherbina Mar 28, 2025
2eeb884
refactor: rename SQL queries
evgeniy-scherbina Mar 28, 2025
73f99e8
refactor: rename fields in SQL query
evgeniy-scherbina Mar 31, 2025
c942753
add tests to ensure workspace builds that include a preset have it se…
SasSwart Apr 1, 2025
9badf7c
test to ensure we mark prebuilds as such
SasSwart Apr 1, 2025
6763ba2
make -B gen fmt
SasSwart Apr 1, 2025
e5117d7
add template_version_preset_id to mock types
SasSwart Apr 1, 2025
dfec884
Merge branch 'prebuilds-db' into 16930
SasSwart Apr 1, 2025
5065ad6
fix dbmem tests
SasSwart Apr 1, 2025
e354956
review notes. mostly rename isPrebuild to prebuild
SasSwart Apr 1, 2025
4d3aab6
Merge remote-tracking branch 'origin/main' into yevhenii/510-reconcil…
evgeniy-scherbina Apr 4, 2025
97b3886
fix dbmem tests
SasSwart Apr 1, 2025
fe60b56
feat: implement reconciliation loop
evgeniy-scherbina Apr 4, 2025
eeb0407
refactor: temporary commit - tests are passing
evgeniy-scherbina Apr 7, 2025
e807d02
refactor: remove DeterminePrebuildsState lock
evgeniy-scherbina Apr 9, 2025
d78675e
refactor: use TryAcquireLock
evgeniy-scherbina Apr 9, 2025
7f60a5d
refactor: Verify ActionType in state_test.go
evgeniy-scherbina Apr 9, 2025
8f5c9f9
refactor: minor refactor
evgeniy-scherbina Apr 9, 2025
42582e1
refactor: minor refactoring
evgeniy-scherbina Apr 9, 2025
14d924c
added comments
evgeniy-scherbina Apr 9, 2025
82e016c
mark prebuilds as such and set their preset ids
SasSwart Mar 17, 2025
c03ea52
add tests to ensure workspace builds that include a preset have it se…
SasSwart Apr 1, 2025
3693d45
test to ensure we mark prebuilds as such
SasSwart Apr 1, 2025
beb814f
make -B gen fmt
SasSwart Apr 1, 2025
a5418ac
add template_version_preset_id to mock types
SasSwart Apr 1, 2025
f4f9b17
fix dbmem tests
SasSwart Apr 1, 2025
d11fd58
go mod tidy && make -B gen
SasSwart Apr 10, 2025
31d3bf6
test: added few more tests
evgeniy-scherbina Apr 10, 2025
5007a83
refactor: remove redundant check for consistency
evgeniy-scherbina Apr 10, 2025
a79fe4c
refactor: use slice.Find instead of slice.Filter for backoff
evgeniy-scherbina Apr 10, 2025
c0246f4
refactor: make sure InProgress works on preset level as well
evgeniy-scherbina Apr 10, 2025
ed608cb
refactor: remove irrelevant comment
evgeniy-scherbina Apr 10, 2025
70223e4
refactor: add BackoffUntil to validateActions func
evgeniy-scherbina Apr 10, 2025
07808c2
refactor: CR's fixes
evgeniy-scherbina Apr 10, 2025
a2ceeb6
refactor: CR's fixes
evgeniy-scherbina Apr 10, 2025
73fb414
Remove todo
evgeniy-scherbina Apr 10, 2025
7e9c65f
minor refactoring
evgeniy-scherbina Apr 10, 2025
2ca8030
refactor: remove deprecated TODOs
evgeniy-scherbina Apr 10, 2025
ce83f92
refactor: slighly adjust comment
evgeniy-scherbina Apr 10, 2025
3bc4d8a
refactor: CR fixes
evgeniy-scherbina Apr 10, 2025
2986574
Remove deprecated TODO
evgeniy-scherbina Apr 10, 2025
aa22a8a
refactor: update comments
evgeniy-scherbina Apr 10, 2025
f41b19e
refactor: remove deprecated TODO
evgeniy-scherbina Apr 10, 2025
61a88e4
deduplicate test and add back proto field
SasSwart Apr 11, 2025
9ac7a2c
refactor: add RunLoop test
evgeniy-scherbina Apr 11, 2025
d0c2094
Merge remote-tracking branch 'origin/16930' into yevhenii/510-reconci…
evgeniy-scherbina Apr 11, 2025
474fc06
Fixes after merge
evgeniy-scherbina Apr 11, 2025
9fac5d7
refactor: simplify SQL query
evgeniy-scherbina Apr 11, 2025
868d0b6
refactor
evgeniy-scherbina Apr 11, 2025
5f204f2
minor fix
evgeniy-scherbina Apr 11, 2025
40b3e5f
minor fix
evgeniy-scherbina Apr 11, 2025
5e3adbc
make fmt
evgeniy-scherbina Apr 11, 2025
108720f
make lint
evgeniy-scherbina Apr 11, 2025
9d8f6b1
chore: fix gpg forwarding test (#17355)
deansheather Apr 11, 2025
b994eec
refactor: fix linter
evgeniy-scherbina Apr 11, 2025
eff754e
refactor: fix linter
evgeniy-scherbina Apr 11, 2025
4b052be
refactor: fix linter
evgeniy-scherbina Apr 11, 2025
bc5297c
refactor: fix linter
evgeniy-scherbina Apr 11, 2025
0989636
refactor: fix linter
evgeniy-scherbina Apr 11, 2025
2b57ac4
refactor: fix linter
evgeniy-scherbina Apr 11, 2025
41d7e07
fix: linter
evgeniy-scherbina Apr 11, 2025
ab5fa8f
fix: linter
evgeniy-scherbina Apr 11, 2025
f485bc0
refactor: fix linter
evgeniy-scherbina Apr 11, 2025
074f768
refactor: fix linter
evgeniy-scherbina Apr 11, 2025
a47627a
refactor: fix imports
evgeniy-scherbina Apr 11, 2025
eebb298
refactor: fix SQL comment
evgeniy-scherbina Apr 14, 2025
9a672dd
refactor: rename dblock
evgeniy-scherbina Apr 14, 2025
c2f4561
Merge remote-tracking branch 'origin/main' into yevhenii/510-reconcil…
evgeniy-scherbina Apr 14, 2025
62fb3f4
refactor: add test when create-prebuild helper fails
evgeniy-scherbina Apr 14, 2025
742d0d3
refactor: add additional check for create-prebuilds flow
evgeniy-scherbina Apr 15, 2025
f3e24b1
refactor: minor fixes in util.go
evgeniy-scherbina Apr 15, 2025
08aed24
refactor: minor fix in noop.go
evgeniy-scherbina Apr 15, 2025
951c8b5
refactor: add TestFilter in util/slice package
evgeniy-scherbina Apr 15, 2025
9c1e82f
refactor: add doc comments
evgeniy-scherbina Apr 15, 2025
46e240c
refactor: update comment
evgeniy-scherbina Apr 16, 2025
6dc1f68
fix: minor bug and add correspoding test
evgeniy-scherbina Apr 16, 2025
23964aa
fix: minor fix for logging
evgeniy-scherbina Apr 16, 2025
0a4d053
fix: CR's fixes
evgeniy-scherbina Apr 16, 2025
98d203d
fix: CR's fixes
evgeniy-scherbina Apr 16, 2025
145b9ff
fix: CR's fixes
evgeniy-scherbina Apr 16, 2025
8b91668
CR's fixes
evgeniy-scherbina Apr 16, 2025
cccdab2
Update coderd/prebuilds/preset_snapshot_test.go
evgeniy-scherbina Apr 16, 2025
a2e5643
Update coderd/prebuilds/preset_snapshot_test.go
evgeniy-scherbina Apr 16, 2025
1771c84
refactor: CR's fixes
evgeniy-scherbina Apr 16, 2025
1fc551d
refactor: CR's fixes
evgeniy-scherbina Apr 16, 2025
d99c5cb
refactor: CR's fixes
evgeniy-scherbina Apr 16, 2025
b98ccd4
fix: make sure prebuild is owned by prebuild user before deleting
evgeniy-scherbina Apr 16, 2025
936cc38
refactor: CR's fixes
evgeniy-scherbina Apr 16, 2025
32da1ab
refactor: CR's fixes
evgeniy-scherbina Apr 16, 2025
5a403c0
Update enterprise/coderd/prebuilds/reconcile.go
evgeniy-scherbina Apr 16, 2025
908e6eb
refactor: CR's fixes
evgeniy-scherbina Apr 16, 2025
77e4472
refactor: CR's fixes
evgeniy-scherbina Apr 17, 2025
853af80
refactor: CR's fixes
evgeniy-scherbina Apr 17, 2025
172177f
Merge remote-tracking branch 'origin/main' into yevhenii/510-reconcil…
evgeniy-scherbina Apr 17, 2025
a825bf0
refactor: reduce number of methods in Reconciler interface
evgeniy-scherbina Apr 17, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions coderd/database/lock.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ const (
LockIDDBPurge
LockIDNotificationsReportGenerator
LockIDCryptoKeyRotation
LockIDReconcileTemplatePrebuilds
LockIDDeterminePrebuildsState
LockIDReconcilePrebuilds
)

// GenLockID generates a unique and consistent lock ID from a given string.
Expand Down
2 changes: 1 addition & 1 deletion coderd/database/querier.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 5 additions & 3 deletions coderd/database/queries.sql.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions coderd/database/queries/prebuilds.sql
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,9 @@ WHERE (b.transition = 'start'::workspace_transition
AND b.job_status = 'succeeded'::provisioner_job_status);

-- name: CountInProgressPrebuilds :many
-- CountInProgressPrebuilds returns the number of in-progress prebuilds, grouped by template version ID and transition.
-- CountInProgressPrebuilds returns the number of in-progress prebuilds, grouped by preset ID and transition.
-- Prebuild considered in-progress if it's in the "starting", "stopping", or "deleting" state.
SELECT t.id AS template_id, wpb.template_version_id, wpb.transition, COUNT(wpb.transition)::int AS count
SELECT t.id AS template_id, wpb.template_version_id, wpb.transition, COUNT(wpb.transition)::int AS count, wlb.template_version_preset_id as preset_id
FROM workspace_latest_builds wlb
INNER JOIN workspace_prebuild_builds wpb ON wpb.id = wlb.id
-- We only need these counts for active template versions.
Expand All @@ -70,7 +70,7 @@ FROM workspace_latest_builds wlb
-- prebuilds that are still building.
INNER JOIN templates t ON t.active_version_id = wlb.template_version_id
WHERE wlb.job_status IN ('pending'::provisioner_job_status, 'running'::provisioner_job_status)
GROUP BY t.id, wpb.template_version_id, wpb.transition;
GROUP BY t.id, wpb.template_version_id, wpb.transition, wlb.template_version_preset_id;

-- GetPresetsBackoff groups workspace builds by preset ID.
-- Each preset is associated with exactly one template version ID.
Expand Down
53 changes: 53 additions & 0 deletions coderd/prebuilds/api.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package prebuilds
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't catch it, but why is prebuilds located in coderd? Are there any components or interfaces used in non-commercial license mode? What I can see here are mainly interfaces and snapshots.

Copy link
Contributor Author

@evgeniy-scherbina evgeniy-scherbina Apr 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess the idea is we have all interfaces and related types defined in coderd. Consequently we have to define methods in the same package. IIRC in goalng you can't define methods outside the package.

@dannykopping should know more

Copy link
Member

@mtojek mtojek Apr 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess the idea is we have all interfaces and related types defined in coderd

Ok, but since prebuilds will be enterprise only, could we just park the entire implementation there?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'll need at least some of the API in the AGPL code because we need the noop implementation "running" until a premium license is used. Other than that, I think most of this can shift to enterprise.

I believe I had it this way because AGPL cannot import enterprise but the reverse is allowed. The interfaces reference the types which are in this package, and if we moved those to enterprise then it would violate the license.

This is how the implementation will be swapped out at runtime based on the license:
https://github.com/coder/coder/blob/dk/prebuilds/enterprise/coderd/coderd.go#L1165-L1188


import (
"context"

"github.com/coder/coder/v2/coderd/database"
)

// ReconciliationOrchestrator manages the lifecycle of prebuild reconciliation.
// It runs a continuous loop to check and reconcile prebuild states, and can be stopped gracefully.
type ReconciliationOrchestrator interface {
Reconciler

// RunLoop starts a continuous reconciliation loop that periodically calls ReconcileAll
// to ensure all prebuilds are in their desired states. The loop runs until the context
// is canceled or Stop is called.
RunLoop(ctx context.Context)

// Stop gracefully shuts down the orchestrator with the given cause.
// The cause is used for logging and error reporting.
Stop(ctx context.Context, cause error)
}

// Reconciler defines the core operations for managing prebuilds.
// It provides both high-level orchestration (ReconcileAll) and lower-level operations
// for more fine-grained control (SnapshotState, ReconcilePreset, CalculateActions).
// All database operations must be performed within repeatable-read transactions
// to ensure consistency.
type Reconciler interface {
Copy link
Contributor Author

@evgeniy-scherbina evgeniy-scherbina Apr 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current API feels too low-level. Ideally, we should expose higher-level methods such as:

  • ReconcileAll()
  • ReconcilePreset(preset)

Note:

  • SnapshotState is currently used only by MetricsCollector.
  • CalculateActions is currently unused.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with this.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's been a couple weeks but I believe we only expose these for tests.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe make it an internal interface and internal test?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a detailed comments, explaining how this API can be used, and why it may sense to expose all these API.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@johnstcn I also wanted to do it, but:

So removing them means:

  • I have to find workaround for tests
  • later we have to find workaround for metrics collector

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no need for this interface to be exported for the metrics collector to work correctly, since it lives in the same package as the StoreReconciler.

Tests can be inside the same package if they need to access unexported functions. Also, you don't need to export an interface to call exported functions on, say, the StoreReconciler.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we do this refactor in a follow-up? Let's try keep the momentum on this PR.

Copy link
Contributor

@spikecurtis spikecurtis Apr 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't agree that "momentum" should be a reason to check in code that doesn't meet our standards. What is to be gained by fixing it later rather than now? IMO it just makes it more likely that we don't fix the issue at all.

Also, this interface isn't actually used anywhere within this PR, so fixing it within the scope of this PR should be trivial.

Copy link
Contributor Author

@evgeniy-scherbina evgeniy-scherbina Apr 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@spikecurtis I reduce number of methods in Reconciler interface.

Now it looks like this:

type Reconciler interface {
	// ReconcileAll orchestrates the reconciliation of all prebuilds across all templates.
	// It takes a global snapshot of the system state and then reconciles each preset
	// in parallel, creating or deleting prebuilds as needed to reach their desired states.
	ReconcileAll(ctx context.Context) error
}

In future PRs maybe we'll need additional methods, but we can deal with it when we'll be working on those PRs.
Also we'll have more information at that point.

cc @dannykopping

// ReconcileAll orchestrates the reconciliation of all prebuilds across all templates.
// It takes a global snapshot of the system state and then reconciles each preset
// in parallel, creating or deleting prebuilds as needed to reach their desired states.
// For more fine-grained control, you can use the lower-level methods SnapshotState
// and ReconcilePreset directly.
ReconcileAll(ctx context.Context) error

// SnapshotState captures the current state of all prebuilds across templates.
// It creates a global database snapshot that can be viewed as a collection of PresetSnapshots,
// each representing the state of prebuilds for a specific preset.
// MUST be called inside a repeatable-read transaction.
SnapshotState(ctx context.Context, store database.Store) (*GlobalSnapshot, error)

// ReconcilePreset handles a single PresetSnapshot, determining and executing
// the required actions (creating or deleting prebuilds) based on the current state.
// MUST be called inside a repeatable-read transaction.
ReconcilePreset(ctx context.Context, snapshot PresetSnapshot) error

// CalculateActions determines what actions are needed to reconcile a preset's prebuilds
// to their desired state. This includes creating new prebuilds, deleting excess ones,
// or waiting due to backoff periods.
// MUST be called inside a repeatable-read transaction.
CalculateActions(ctx context.Context, state PresetSnapshot) (*ReconciliationActions, error)
}
66 changes: 66 additions & 0 deletions coderd/prebuilds/global_snapshot.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package prebuilds

import (
"github.com/google/uuid"
"golang.org/x/xerrors"

"github.com/coder/coder/v2/coderd/database"
"github.com/coder/coder/v2/coderd/util/slice"
)

// GlobalSnapshot represents a full point-in-time snapshot of state relating to prebuilds across all templates.
type GlobalSnapshot struct {
Presets []database.GetTemplatePresetsWithPrebuildsRow
RunningPrebuilds []database.GetRunningPrebuiltWorkspacesRow
PrebuildsInProgress []database.CountInProgressPrebuildsRow
Backoffs []database.GetPresetsBackoffRow
}

func NewGlobalSnapshot(
presets []database.GetTemplatePresetsWithPrebuildsRow,
runningPrebuilds []database.GetRunningPrebuiltWorkspacesRow,
prebuildsInProgress []database.CountInProgressPrebuildsRow,
backoffs []database.GetPresetsBackoffRow,
) GlobalSnapshot {
return GlobalSnapshot{
Presets: presets,
RunningPrebuilds: runningPrebuilds,
PrebuildsInProgress: prebuildsInProgress,
Backoffs: backoffs,
}
}
Comment on lines +19 to +31
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: this could probably be removed; I only see it used in one other place and it doesn't seem to provide any ergonomic benefits over snap := GlobalSnapshot{...}.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally I like constructors in Go, because if later we'll add new field to GlobalSnapshot, we can update constructor and easily track and update all object creations.
We can add validation inside constructor, etc...


func (s GlobalSnapshot) FilterByPreset(presetID uuid.UUID) (*PresetSnapshot, error) {
preset, found := slice.Find(s.Presets, func(preset database.GetTemplatePresetsWithPrebuildsRow) bool {
return preset.ID == presetID
})
if !found {
return nil, xerrors.Errorf("no preset found with ID %q", presetID)
}

running := slice.Filter(s.RunningPrebuilds, func(prebuild database.GetRunningPrebuiltWorkspacesRow) bool {
if !prebuild.CurrentPresetID.Valid {
return false
}
return prebuild.CurrentPresetID.UUID == preset.ID
})

inProgress := slice.Filter(s.PrebuildsInProgress, func(prebuild database.CountInProgressPrebuildsRow) bool {
return prebuild.PresetID.UUID == preset.ID
})

var backoffPtr *database.GetPresetsBackoffRow
backoff, found := slice.Find(s.Backoffs, func(row database.GetPresetsBackoffRow) bool {
return row.PresetID == preset.ID
})
if found {
backoffPtr = &backoff
}

return &PresetSnapshot{
Preset: preset,
Running: running,
InProgress: inProgress,
Backoff: backoffPtr,
}, nil
}
35 changes: 35 additions & 0 deletions coderd/prebuilds/noop.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package prebuilds

import (
"context"

"github.com/coder/coder/v2/coderd/database"
)

type NoopReconciler struct{}

func NewNoopReconciler() *NoopReconciler {
return &NoopReconciler{}
}

func (NoopReconciler) RunLoop(context.Context) {}

func (NoopReconciler) Stop(context.Context, error) {}

func (NoopReconciler) ReconcileAll(context.Context) error {
return nil
}

func (NoopReconciler) SnapshotState(context.Context, database.Store) (*GlobalSnapshot, error) {
return &GlobalSnapshot{}, nil
}

func (NoopReconciler) ReconcilePreset(context.Context, PresetSnapshot) error {
return nil
}

func (NoopReconciler) CalculateActions(context.Context, PresetSnapshot) (*ReconciliationActions, error) {
return &ReconciliationActions{}, nil
}

var _ ReconciliationOrchestrator = NoopReconciler{}
Loading
Loading