@@ -11,6 +11,119 @@ import (
11
11
)
12
12
13
13
func (p PresetState ) CalculateActions (clock quartz.Clock , backoffInterval time.Duration ) (* ReconciliationActions , error ) {
14
+
15
+ switch {
16
+ //case inBackoffPeriod():
17
+ // return handleBackoff()
18
+ //case isDeprecated():
19
+ // return handleDeprecatedTemplateVersion()
20
+ case p .Preset .UsingActiveVersion :
21
+ handleActiveTemplateVersion ()
22
+ //case x:
23
+ // handleInactiveTemplateVersion()
24
+ }
25
+ }
26
+
27
+ func (p PresetState ) handleActiveTemplateVersion () (* ReconciliationActions , error ) {
28
+ var (
29
+ actual int32 // Running prebuilds for active version.
30
+ desired int32 // Active template version's desired instances as defined in preset.
31
+ eligible int32 // Prebuilds which can be claimed.
32
+ outdated int32 // Prebuilds which no longer match the active template version.
33
+ extraneous int32 // Extra running prebuilds for active version (somehow).
34
+ starting , stopping , deleting int32 // Prebuilds currently being provisioned up or down.
35
+ )
36
+
37
+ actual = int32 (len (p .Running ))
38
+ desired = p .Preset .DesiredInstances
39
+ extraneous = max (actual - p .Preset .DesiredInstances , 0 )
40
+
41
+ for _ , prebuild := range p .Running {
42
+ if prebuild .Ready {
43
+ eligible ++
44
+ }
45
+ }
46
+
47
+ // In-progress builds are common across all presets belonging to a given template.
48
+ // In other words: these values will be identical across all presets belonging to this template.
49
+ // TODO: put in a helper method?
50
+ for _ , progress := range p .InProgress {
51
+ num := progress .Count
52
+ switch progress .Transition {
53
+ case database .WorkspaceTransitionStart :
54
+ starting += num
55
+ case database .WorkspaceTransitionStop :
56
+ stopping += num
57
+ case database .WorkspaceTransitionDelete :
58
+ deleting += num
59
+ }
60
+ }
61
+
62
+ var (
63
+ toCreate = int (math .Max (0 , float64 (
64
+ desired - (actual + starting )), // The number of prebuilds currently being stopped (should be 0)
65
+ ))
66
+ //toDelete = int(math.Max(0, float64(
67
+ // outdated- // The number of prebuilds running above the desired count for active version
68
+ // deleting), // The number of prebuilds currently being deleted
69
+ //))
70
+
71
+ actions = & ReconciliationActions {
72
+ Actual : actual ,
73
+ Desired : desired ,
74
+ Eligible : eligible ,
75
+ Outdated : outdated ,
76
+ Extraneous : extraneous ,
77
+ Starting : starting ,
78
+ Stopping : stopping ,
79
+ Deleting : deleting ,
80
+ }
81
+ )
82
+
83
+ // It's possible that an operator could stop/start prebuilds which interfere with the reconciliation loop, so
84
+ // we check if there are somehow more prebuilds than we expect, and then pick random victims to be deleted.
85
+ if extraneous > 0 {
86
+ // Sort running IDs by creation time so we always delete the oldest prebuilds.
87
+ // In general, we want fresher prebuilds (imagine a mono-repo is cloned; newer is better).
88
+ slices .SortFunc (p .Running , func (a , b database.GetRunningPrebuildsRow ) int {
89
+ if a .CreatedAt .Before (b .CreatedAt ) {
90
+ return - 1
91
+ }
92
+ if a .CreatedAt .After (b .CreatedAt ) {
93
+ return 1
94
+ }
95
+
96
+ return 0
97
+ })
98
+
99
+ for i := 0 ; i < int (extraneous ); i ++ {
100
+ if i >= len (p .Running ) {
101
+ // This should never happen.
102
+ // TODO: move up
103
+ // c.logger.Warn(ctx, "unexpected reconciliation state; extraneous count exceeds running prebuilds count!",
104
+ // slog.F("running_count", len(p.Running)),
105
+ // slog.F("extraneous", extraneous))
106
+ continue
107
+ }
108
+
109
+ actions .DeleteIDs = append (actions .DeleteIDs , p .Running [i ].WorkspaceID )
110
+ }
111
+
112
+ // TODO: move up
113
+ // c.logger.Warn(ctx, "found extra prebuilds running, picking random victim(s)",
114
+ // slog.F("template_id", p.Preset.TemplateID.String()), slog.F("desired", desired), slog.F("actual", actual), slog.F("extra", extraneous),
115
+ // slog.F("victims", victims))
116
+
117
+ // Prevent the rest of the reconciliation from completing
118
+ return actions , nil
119
+ }
120
+
121
+ actions .Create = int32 (toCreate )
122
+
123
+ return actions , nil
124
+ }
125
+
126
+ func (p PresetState ) CalculateActionsV0 (clock quartz.Clock , backoffInterval time.Duration ) (* ReconciliationActions , error ) {
14
127
// TODO: align workspace states with how we represent them on the FE and the CLI
15
128
// right now there's some slight differences which can lead to additional prebuilds being created
16
129
0 commit comments