@highstate/backend 0.9.15 → 0.9.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-NAAIDR4U.js +8499 -0
- package/dist/chunk-NAAIDR4U.js.map +1 -0
- package/dist/chunk-OU5OQBLB.js +74 -0
- package/dist/chunk-OU5OQBLB.js.map +1 -0
- package/dist/chunk-Y7DXREVO.js +1745 -0
- package/dist/chunk-Y7DXREVO.js.map +1 -0
- package/dist/highstate.manifest.json +4 -4
- package/dist/index.js +7227 -2501
- package/dist/index.js.map +1 -1
- package/dist/library/package-resolution-worker.js +7 -5
- package/dist/library/package-resolution-worker.js.map +1 -1
- package/dist/library/worker/main.js +76 -185
- package/dist/library/worker/main.js.map +1 -1
- package/dist/magic-string.es-5ABAC4JN.js +1292 -0
- package/dist/magic-string.es-5ABAC4JN.js.map +1 -0
- package/dist/shared/index.js +3 -98
- package/dist/shared/index.js.map +1 -1
- package/package.json +31 -10
- package/src/artifact/abstractions.ts +46 -0
- package/src/artifact/encryption.ts +109 -0
- package/src/artifact/factory.ts +36 -0
- package/src/artifact/index.ts +3 -0
- package/src/artifact/local.ts +138 -0
- package/src/business/__traces__/secret/update-instance-secrets/create-and-delete-secrets-simultaneously.md +356 -0
- package/src/business/__traces__/secret/update-instance-secrets/create-new-secrets-for-instance.md +274 -0
- package/src/business/__traces__/secret/update-instance-secrets/delete-existing-secrets.md +223 -0
- package/src/business/__traces__/secret/update-instance-secrets/no-op-when-no-changes.md +147 -0
- package/src/business/__traces__/secret/update-instance-secrets/update-existing-secrets.md +280 -0
- package/src/business/__traces__/worker/update-unit-registrations/add-new-unit-registration-when-other-exists.md +360 -0
- package/src/business/__traces__/worker/update-unit-registrations/add-new-unit-registration.md +215 -0
- package/src/business/__traces__/worker/update-unit-registrations/create-multiple-workers-with-different-identities.md +427 -0
- package/src/business/__traces__/worker/update-unit-registrations/handle-nonexistent-registration-id-gracefully.md +217 -0
- package/src/business/__traces__/worker/update-unit-registrations/no-op-when-no-changes.md +132 -0
- package/src/business/__traces__/worker/update-unit-registrations/recreate-worker-when-image-changes.md +454 -0
- package/src/business/__traces__/worker/update-unit-registrations/recreate-worker-when-image-version-changes.md +426 -0
- package/src/business/__traces__/worker/update-unit-registrations/recreate-worker-with-same-identity-reuses-service-account.md +372 -0
- package/src/business/__traces__/worker/update-unit-registrations/remove-one-of-multiple-unit-registrations.md +383 -0
- package/src/business/__traces__/worker/update-unit-registrations/remove-unit-registration.md +245 -0
- package/src/business/__traces__/worker/update-unit-registrations/update-existing-unit-registration-when-params-change.md +174 -0
- package/src/business/__traces__/worker/update-unit-registrations/update-params-and-image-simultaneously.md +432 -0
- package/src/business/__traces__/worker/update-unit-registrations/worker-with-multiple-registrations-not-deleted-when-one-removed.md +220 -0
- package/src/business/api-key.ts +65 -0
- package/src/business/artifact.ts +289 -0
- package/src/business/backend-unlock.ts +10 -0
- package/src/business/index.ts +10 -0
- package/src/business/instance-lock.ts +125 -0
- package/src/business/instance-state.ts +434 -0
- package/src/business/operation.ts +251 -0
- package/src/business/project-unlock.ts +260 -0
- package/src/business/project.ts +299 -0
- package/src/business/secret.test.ts +178 -0
- package/src/business/secret.ts +281 -0
- package/src/business/worker.test.ts +614 -0
- package/src/business/worker.ts +398 -0
- package/src/common/clock.ts +18 -0
- package/src/common/index.ts +5 -1
- package/src/common/performance.ts +44 -0
- package/src/common/random.ts +68 -0
- package/src/common/test/index.ts +2 -0
- package/src/common/test/render.ts +98 -0
- package/src/common/test/tracer.ts +359 -0
- package/src/common/tree.ts +33 -0
- package/src/common/utils.ts +40 -1
- package/src/config.ts +19 -11
- package/src/hotstate/abstractions.ts +48 -0
- package/src/hotstate/factory.ts +17 -0
- package/src/{secret → hotstate}/index.ts +1 -0
- package/src/hotstate/manager.ts +192 -0
- package/src/hotstate/memory.ts +100 -0
- package/src/hotstate/validation.ts +100 -0
- package/src/index.ts +2 -1
- package/src/library/abstractions.ts +24 -28
- package/src/library/factory.ts +2 -2
- package/src/library/local.ts +91 -111
- package/src/library/worker/evaluator.ts +36 -73
- package/src/library/worker/loader.lite.ts +54 -0
- package/src/library/worker/main.ts +15 -66
- package/src/library/worker/protocol.ts +6 -33
- package/src/lock/abstractions.ts +6 -0
- package/src/lock/factory.ts +15 -0
- package/src/lock/index.ts +4 -0
- package/src/lock/manager.ts +97 -0
- package/src/lock/memory.ts +19 -0
- package/src/lock/test.ts +108 -0
- package/src/orchestrator/manager.ts +118 -90
- package/src/orchestrator/operation-workset.ts +181 -93
- package/src/orchestrator/operation.ts +1021 -283
- package/src/project/abstractions.ts +27 -38
- package/src/project/evaluation.ts +248 -0
- package/src/project/factory.ts +1 -1
- package/src/project/index.ts +1 -2
- package/src/project/local.ts +107 -103
- package/src/pubsub/abstractions.ts +13 -0
- package/src/pubsub/factory.ts +19 -0
- package/src/{workspace → pubsub}/index.ts +1 -0
- package/src/pubsub/local.ts +36 -0
- package/src/pubsub/manager.ts +108 -0
- package/src/pubsub/validation.ts +33 -0
- package/src/runner/abstractions.ts +155 -68
- package/src/runner/artifact-env.ts +160 -0
- package/src/runner/factory.ts +20 -5
- package/src/runner/force-abort.ts +117 -0
- package/src/runner/local.ts +292 -372
- package/src/{common → runner}/pulumi.ts +89 -37
- package/src/services.ts +251 -40
- package/src/shared/index.ts +3 -11
- package/src/shared/models/backend/index.ts +3 -0
- package/src/shared/{library.ts → models/backend/library.ts} +4 -4
- package/src/shared/models/backend/project.ts +82 -0
- package/src/shared/models/backend/unlock-method.ts +20 -0
- package/src/shared/models/base.ts +68 -0
- package/src/shared/models/errors.ts +5 -0
- package/src/shared/models/index.ts +4 -0
- package/src/shared/models/project/api-key.ts +65 -0
- package/src/shared/models/project/artifact.ts +83 -0
- package/src/shared/models/project/index.ts +13 -0
- package/src/shared/models/project/lock.ts +91 -0
- package/src/shared/models/project/model.ts +14 -0
- package/src/shared/{operation.ts → models/project/operation.ts} +29 -8
- package/src/shared/models/project/page.ts +57 -0
- package/src/shared/models/project/secret.ts +98 -0
- package/src/shared/models/project/service-account.ts +22 -0
- package/src/shared/models/project/state.ts +449 -0
- package/src/shared/models/project/terminal.ts +98 -0
- package/src/shared/models/project/trigger.ts +56 -0
- package/src/shared/models/project/unlock-method.ts +38 -0
- package/src/shared/models/project/worker.ts +107 -0
- package/src/shared/resolvers/graph-resolver.ts +61 -18
- package/src/shared/resolvers/index.ts +5 -0
- package/src/shared/resolvers/input-hash.ts +53 -15
- package/src/shared/resolvers/input.ts +47 -13
- package/src/shared/resolvers/registry.ts +3 -2
- package/src/shared/resolvers/state.ts +2 -2
- package/src/shared/resolvers/validation.ts +82 -25
- package/src/shared/utils/args.ts +25 -0
- package/src/shared/{async-batcher.ts → utils/async-batcher.ts} +13 -1
- package/src/shared/utils/hash.ts +6 -0
- package/src/shared/utils/index.ts +4 -0
- package/src/shared/utils/promise-tracker.ts +23 -0
- package/src/state/abstractions.ts +199 -131
- package/src/state/encryption.ts +98 -0
- package/src/state/factory.ts +3 -5
- package/src/state/index.ts +4 -0
- package/src/state/keyring.ts +22 -0
- package/src/state/local/backend.ts +106 -0
- package/src/state/local/collection.ts +361 -0
- package/src/state/local/index.ts +2 -0
- package/src/state/manager.ts +875 -18
- package/src/state/memory/backend.ts +70 -0
- package/src/state/memory/collection.ts +270 -0
- package/src/state/memory/index.ts +2 -0
- package/src/state/repository/index.ts +2 -0
- package/src/state/repository/repository.index.ts +193 -0
- package/src/state/repository/repository.ts +507 -0
- package/src/state/test.ts +457 -0
- package/src/terminal/{shared.ts → abstractions.ts} +3 -3
- package/src/terminal/docker.ts +18 -14
- package/src/terminal/factory.ts +3 -3
- package/src/terminal/index.ts +1 -1
- package/src/terminal/manager.ts +131 -79
- package/src/terminal/run.sh.ts +21 -11
- package/src/unlock/abstractions.ts +49 -0
- package/src/unlock/index.ts +2 -0
- package/src/unlock/memory.ts +32 -0
- package/src/worker/abstractions.ts +42 -0
- package/src/worker/docker.ts +83 -0
- package/src/worker/factory.ts +20 -0
- package/src/worker/index.ts +3 -0
- package/src/worker/manager.ts +167 -0
- package/dist/chunk-KTGKNSKM.js +0 -979
- package/dist/chunk-KTGKNSKM.js.map +0 -1
- package/dist/chunk-WXDYCRTT.js +0 -234
- package/dist/chunk-WXDYCRTT.js.map +0 -1
- package/src/library/worker/loader.ts +0 -114
- package/src/preferences/shared.ts +0 -1
- package/src/project/lock.ts +0 -39
- package/src/project/manager.ts +0 -433
- package/src/secret/abstractions.ts +0 -59
- package/src/secret/factory.ts +0 -22
- package/src/secret/local.ts +0 -152
- package/src/shared/project.ts +0 -62
- package/src/shared/state.ts +0 -247
- package/src/shared/terminal.ts +0 -14
- package/src/state/local.ts +0 -612
- package/src/workspace/abstractions.ts +0 -41
- package/src/workspace/factory.ts +0 -14
- package/src/workspace/local.ts +0 -54
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import type { LibraryBackend } from "../library"
|
|
2
2
|
import type { ProjectBackend } from "../project"
|
|
3
|
-
import type {
|
|
3
|
+
import type { StateManager } from "../state"
|
|
4
4
|
import type { Logger } from "pino"
|
|
5
|
+
import type { InstanceLockService, InstanceStateService } from "../business"
|
|
6
|
+
import { EventEmitter, on } from "node:events"
|
|
5
7
|
import {
|
|
6
8
|
isUnitModel,
|
|
7
9
|
parseInstanceId,
|
|
@@ -11,24 +13,26 @@ import {
|
|
|
11
13
|
import { unique } from "remeda"
|
|
12
14
|
import { BetterLock } from "better-lock"
|
|
13
15
|
import {
|
|
14
|
-
applyPartialInstanceState,
|
|
15
|
-
createInstanceState,
|
|
16
|
-
createInstanceStatePatch,
|
|
17
16
|
InputHashResolver,
|
|
18
17
|
InputResolver,
|
|
19
18
|
type InputHashNode,
|
|
19
|
+
type InputHashOutput,
|
|
20
20
|
type InputResolverNode,
|
|
21
|
+
type InstanceOperataionStatusEnum,
|
|
21
22
|
type InstanceState,
|
|
22
|
-
type
|
|
23
|
-
type InstanceStatus,
|
|
23
|
+
type InstanceStatePatch,
|
|
24
24
|
type LibraryModel,
|
|
25
|
-
type
|
|
25
|
+
type Operation,
|
|
26
|
+
type Project,
|
|
26
27
|
type ResolvedInstanceInput,
|
|
27
28
|
} from "../shared"
|
|
28
29
|
|
|
29
30
|
export type OperationPhase = "update" | "destroy" | "refresh"
|
|
30
31
|
|
|
31
32
|
export class OperationWorkset {
|
|
33
|
+
private readonly lockedInstanceIds = new Set<string>()
|
|
34
|
+
public readonly instanceIdsToLockIds = new Set<string>()
|
|
35
|
+
|
|
32
36
|
private readonly instanceIdsToUpdate = new Set<string>()
|
|
33
37
|
private readonly instanceIdsToDestroy = new Set<string>()
|
|
34
38
|
|
|
@@ -40,7 +44,7 @@ export class OperationWorkset {
|
|
|
40
44
|
private readonly dependentStateIdMap = new Map<string, Set<string>>()
|
|
41
45
|
private readonly stateChildIdMap = new Map<string, string[]>()
|
|
42
46
|
|
|
43
|
-
private readonly unitSourceHashMap = new Map<string,
|
|
47
|
+
private readonly unitSourceHashMap = new Map<string, number>()
|
|
44
48
|
|
|
45
49
|
private inputResolver!: InputResolver
|
|
46
50
|
private readonly inputResolverNodes = new Map<string, InputResolverNode>()
|
|
@@ -54,13 +58,29 @@ export class OperationWorkset {
|
|
|
54
58
|
Record<string, ResolvedInstanceInput[]>
|
|
55
59
|
>()
|
|
56
60
|
|
|
61
|
+
public currentPhase!: OperationPhase
|
|
62
|
+
|
|
63
|
+
private readonly lockEventEmitter = new EventEmitter()
|
|
64
|
+
|
|
57
65
|
private constructor(
|
|
58
|
-
public readonly
|
|
66
|
+
public readonly project: Project,
|
|
67
|
+
public readonly operation: Operation,
|
|
59
68
|
public readonly library: LibraryModel,
|
|
60
|
-
private readonly
|
|
69
|
+
private readonly instanceLockService: InstanceLockService,
|
|
70
|
+
private readonly instanceStateService: InstanceStateService,
|
|
61
71
|
private readonly logger: Logger,
|
|
62
72
|
) {}
|
|
63
73
|
|
|
74
|
+
public async ensureInstanceLocked(instanceId: string, signal: AbortSignal): Promise<void> {
|
|
75
|
+
if (this.lockedInstanceIds.has(instanceId)) {
|
|
76
|
+
return
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
for await (const _ of on(this.lockEventEmitter, instanceId, { signal })) {
|
|
80
|
+
return
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
64
84
|
public getInstance(instanceId: string): InstanceModel {
|
|
65
85
|
const instance = this.instanceMap.get(instanceId)
|
|
66
86
|
if (!instance) {
|
|
@@ -70,35 +90,43 @@ export class OperationWorkset {
|
|
|
70
90
|
return instance
|
|
71
91
|
}
|
|
72
92
|
|
|
73
|
-
public getAffectedInstanceIds(
|
|
74
|
-
if (
|
|
93
|
+
public getAffectedInstanceIds(): string[] {
|
|
94
|
+
if (this.currentPhase === "destroy") {
|
|
75
95
|
return Array.from(this.instanceIdsToDestroy)
|
|
76
96
|
}
|
|
77
97
|
|
|
78
98
|
return Array.from(this.instanceIdsToUpdate)
|
|
79
99
|
}
|
|
80
100
|
|
|
101
|
+
public getAllAffectedInstanceIds(): string[] {
|
|
102
|
+
return Array.from(this.instanceIdsToUpdate.union(this.instanceIdsToDestroy))
|
|
103
|
+
}
|
|
104
|
+
|
|
81
105
|
public getInstanceOrUndefined(instanceId: string): InstanceModel | undefined {
|
|
82
106
|
return this.instanceMap.get(instanceId)
|
|
83
107
|
}
|
|
84
108
|
|
|
85
|
-
public isAffected(instanceId: string
|
|
86
|
-
if (
|
|
109
|
+
public isAffected(instanceId: string): boolean {
|
|
110
|
+
if (this.currentPhase === "destroy") {
|
|
87
111
|
return this.instanceIdsToDestroy.has(instanceId)
|
|
88
112
|
}
|
|
89
113
|
|
|
90
114
|
return this.instanceIdsToUpdate.has(instanceId)
|
|
91
115
|
}
|
|
92
116
|
|
|
93
|
-
public
|
|
94
|
-
const
|
|
95
|
-
|
|
117
|
+
public async patchState(patch: InstanceStatePatch): Promise<InstanceState> {
|
|
118
|
+
const state = await this.instanceStateService.patchOperationInstanceState(
|
|
119
|
+
this.project.id,
|
|
120
|
+
this.operation,
|
|
121
|
+
patch,
|
|
122
|
+
)
|
|
123
|
+
this.stateMap.set(state.id, state)
|
|
96
124
|
|
|
97
|
-
if (
|
|
98
|
-
this.recalculateCompositeInstanceState(
|
|
125
|
+
if (state.parentId) {
|
|
126
|
+
await this.recalculateCompositeInstanceState(state.parentId)
|
|
99
127
|
}
|
|
100
128
|
|
|
101
|
-
return
|
|
129
|
+
return state
|
|
102
130
|
}
|
|
103
131
|
|
|
104
132
|
public setState(state: InstanceState): void {
|
|
@@ -115,7 +143,7 @@ export class OperationWorkset {
|
|
|
115
143
|
children.push(state.id)
|
|
116
144
|
}
|
|
117
145
|
|
|
118
|
-
for (const dependencyId of state.dependencyIds) {
|
|
146
|
+
for (const dependencyId of state.operationStatus?.dependencyIds ?? []) {
|
|
119
147
|
this.addDependentState(state.id, dependencyId)
|
|
120
148
|
}
|
|
121
149
|
}
|
|
@@ -131,35 +159,52 @@ export class OperationWorkset {
|
|
|
131
159
|
dependentStates.add(instanceId)
|
|
132
160
|
}
|
|
133
161
|
|
|
134
|
-
public
|
|
135
|
-
const
|
|
136
|
-
const initialState = this.initialStateMap.get(instanceId)
|
|
162
|
+
public async restoreInitialState(instanceId: string): Promise<void> {
|
|
163
|
+
const initialState = this.initialStateMap.get(instanceId) ?? { id: instanceId }
|
|
137
164
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
}
|
|
165
|
+
this.logger.debug(
|
|
166
|
+
{ initialState },
|
|
167
|
+
`resetting state for instance "%s" to initial state`,
|
|
168
|
+
instanceId,
|
|
169
|
+
)
|
|
144
170
|
|
|
145
|
-
this.
|
|
171
|
+
await this.instanceStateService.updateInstanceStates(
|
|
172
|
+
this.project.id,
|
|
173
|
+
[initialState],
|
|
174
|
+
true,
|
|
175
|
+
false,
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
if (initialState.parentId) {
|
|
179
|
+
await this.recalculateCompositeInstanceState(initialState.parentId)
|
|
180
|
+
}
|
|
146
181
|
}
|
|
147
182
|
|
|
148
|
-
public
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
183
|
+
public async restoreAffectedInitialStates(): Promise<void> {
|
|
184
|
+
const instanceStates: InstanceState[] = []
|
|
185
|
+
|
|
186
|
+
for (const instanceId of this.getAffectedInstanceIds()) {
|
|
187
|
+
const state = this.initialStateMap.get(instanceId)
|
|
188
|
+
if (state) {
|
|
189
|
+
instanceStates.push(state)
|
|
152
190
|
}
|
|
153
191
|
}
|
|
192
|
+
|
|
193
|
+
await this.instanceStateService.updateInstanceStates(
|
|
194
|
+
this.project.id,
|
|
195
|
+
instanceStates,
|
|
196
|
+
false,
|
|
197
|
+
false,
|
|
198
|
+
)
|
|
154
199
|
}
|
|
155
200
|
|
|
156
|
-
public getAffectedCompositeChildren(instanceId: string
|
|
201
|
+
public getAffectedCompositeChildren(instanceId: string): InstanceModel[] {
|
|
157
202
|
const children = this.instanceChildrenMap.get(instanceId)
|
|
158
203
|
if (!children) {
|
|
159
204
|
return []
|
|
160
205
|
}
|
|
161
206
|
|
|
162
|
-
if (
|
|
207
|
+
if (this.currentPhase === "destroy") {
|
|
163
208
|
return children.filter(child => this.instanceIdsToDestroy.has(child.id))
|
|
164
209
|
}
|
|
165
210
|
|
|
@@ -170,11 +215,11 @@ export class OperationWorkset {
|
|
|
170
215
|
return this.stateMap.get(instanceId)
|
|
171
216
|
}
|
|
172
217
|
|
|
173
|
-
public getParentId(instanceId: string
|
|
174
|
-
if (
|
|
218
|
+
public getParentId(instanceId: string): string | undefined {
|
|
219
|
+
if (this.currentPhase === "destroy") {
|
|
175
220
|
const state = this.stateMap.get(instanceId)
|
|
176
221
|
if (!state) {
|
|
177
|
-
return
|
|
222
|
+
return undefined
|
|
178
223
|
}
|
|
179
224
|
|
|
180
225
|
return state.parentId
|
|
@@ -182,7 +227,7 @@ export class OperationWorkset {
|
|
|
182
227
|
|
|
183
228
|
const instance = this.getInstance(instanceId)
|
|
184
229
|
|
|
185
|
-
return instance.parentId
|
|
230
|
+
return instance.parentId
|
|
186
231
|
}
|
|
187
232
|
|
|
188
233
|
public getDependentStates(instanceId: string): InstanceState[] {
|
|
@@ -196,8 +241,15 @@ export class OperationWorkset {
|
|
|
196
241
|
.filter((state): state is InstanceState => !!state)
|
|
197
242
|
}
|
|
198
243
|
|
|
199
|
-
private recalculateCompositeInstanceState(instanceId: string
|
|
200
|
-
const state = this.stateMap.get(instanceId)
|
|
244
|
+
private async recalculateCompositeInstanceState(instanceId: string): Promise<void> {
|
|
245
|
+
const state = this.stateMap.get(instanceId)
|
|
246
|
+
if (!state) {
|
|
247
|
+
this.logger.warn(
|
|
248
|
+
`cannot recalculate composite instance state for "${instanceId}" because it is not in the state map`,
|
|
249
|
+
)
|
|
250
|
+
return
|
|
251
|
+
}
|
|
252
|
+
|
|
201
253
|
let currentResourceCount = 0
|
|
202
254
|
let totalResourceCount = 0
|
|
203
255
|
|
|
@@ -205,28 +257,25 @@ export class OperationWorkset {
|
|
|
205
257
|
for (const childId of children) {
|
|
206
258
|
const child = this.stateMap.get(childId)
|
|
207
259
|
|
|
208
|
-
if (child?.currentResourceCount) {
|
|
209
|
-
currentResourceCount += child.currentResourceCount
|
|
260
|
+
if (child?.operationStatus?.currentResourceCount) {
|
|
261
|
+
currentResourceCount += child.operationStatus.currentResourceCount
|
|
210
262
|
}
|
|
211
263
|
|
|
212
|
-
if (child?.totalResourceCount) {
|
|
213
|
-
totalResourceCount += child.totalResourceCount
|
|
264
|
+
if (child?.operationStatus?.totalResourceCount) {
|
|
265
|
+
totalResourceCount += child.operationStatus?.totalResourceCount
|
|
214
266
|
}
|
|
215
267
|
}
|
|
216
268
|
|
|
217
|
-
const
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
269
|
+
const patch: InstanceStatePatch = {
|
|
270
|
+
id: instanceId,
|
|
271
|
+
operationStatus: {
|
|
272
|
+
status: this.getTransientStatusByOperationPhase(),
|
|
273
|
+
currentResourceCount,
|
|
274
|
+
totalResourceCount,
|
|
275
|
+
},
|
|
222
276
|
}
|
|
223
277
|
|
|
224
|
-
this.
|
|
225
|
-
this.stateManager.emitStatePatch(this.operation.projectId, updatedState)
|
|
226
|
-
|
|
227
|
-
if (state.parentId) {
|
|
228
|
-
this.recalculateCompositeInstanceState(state.parentId, phase)
|
|
229
|
-
}
|
|
278
|
+
await this.patchState(patch)
|
|
230
279
|
}
|
|
231
280
|
|
|
232
281
|
private addInstance(instance: InstanceModel): void {
|
|
@@ -281,7 +330,11 @@ export class OperationWorkset {
|
|
|
281
330
|
return
|
|
282
331
|
}
|
|
283
332
|
|
|
284
|
-
if (
|
|
333
|
+
if (
|
|
334
|
+
!state?.operationStatus ||
|
|
335
|
+
state.operationStatus.status === "error" ||
|
|
336
|
+
state.operationStatus.inputHash !== expectedInputHash
|
|
337
|
+
) {
|
|
285
338
|
this.instanceIdsToUpdate.add(instanceId)
|
|
286
339
|
}
|
|
287
340
|
}
|
|
@@ -312,7 +365,11 @@ export class OperationWorkset {
|
|
|
312
365
|
const state = this.stateMap.get(child.id)
|
|
313
366
|
const { inputHash: expectedInputHash } = this.inputHashResolver.requireOutput(child.id)
|
|
314
367
|
|
|
315
|
-
if (
|
|
368
|
+
if (
|
|
369
|
+
!state?.operationStatus ||
|
|
370
|
+
state.operationStatus.status === "error" ||
|
|
371
|
+
state.operationStatus.inputHash !== expectedInputHash
|
|
372
|
+
) {
|
|
316
373
|
this.instanceIdsToUpdate.add(child.id)
|
|
317
374
|
}
|
|
318
375
|
}
|
|
@@ -347,7 +404,7 @@ export class OperationWorkset {
|
|
|
347
404
|
}
|
|
348
405
|
|
|
349
406
|
const state = this.stateMap.get(instanceKey)
|
|
350
|
-
if (!state
|
|
407
|
+
if (!state) {
|
|
351
408
|
return
|
|
352
409
|
}
|
|
353
410
|
|
|
@@ -438,7 +495,7 @@ export class OperationWorkset {
|
|
|
438
495
|
private getSourceHashIfApplicable(
|
|
439
496
|
instance: InstanceModel,
|
|
440
497
|
component: ComponentModel,
|
|
441
|
-
):
|
|
498
|
+
): number | undefined {
|
|
442
499
|
if (isUnitModel(component)) {
|
|
443
500
|
return this.unitSourceHashMap.get(instance.type)
|
|
444
501
|
}
|
|
@@ -446,8 +503,8 @@ export class OperationWorkset {
|
|
|
446
503
|
return undefined
|
|
447
504
|
}
|
|
448
505
|
|
|
449
|
-
private
|
|
450
|
-
switch (
|
|
506
|
+
private getTransientStatusByOperationPhase(): InstanceOperataionStatusEnum {
|
|
507
|
+
switch (this.currentPhase) {
|
|
451
508
|
case "update":
|
|
452
509
|
return "updating"
|
|
453
510
|
case "destroy":
|
|
@@ -457,7 +514,7 @@ export class OperationWorkset {
|
|
|
457
514
|
}
|
|
458
515
|
}
|
|
459
516
|
|
|
460
|
-
public async
|
|
517
|
+
public async getUpToDateInputHashOutput(instance: InstanceModel): Promise<InputHashOutput> {
|
|
461
518
|
return await this.inputHashResolverLock.acquire(async () => {
|
|
462
519
|
const component = this.library.components[instance.type]
|
|
463
520
|
|
|
@@ -472,67 +529,90 @@ export class OperationWorkset {
|
|
|
472
529
|
this.inputHashResolver.invalidate(instance.id)
|
|
473
530
|
await this.inputHashResolver.process()
|
|
474
531
|
|
|
475
|
-
|
|
476
|
-
return inputHash
|
|
532
|
+
return this.inputHashResolver.requireOutput(instance.id)
|
|
477
533
|
})
|
|
478
534
|
}
|
|
479
535
|
|
|
480
|
-
|
|
481
|
-
|
|
536
|
+
/**
|
|
537
|
+
* Tries to acquire not-locked instances in the workset.
|
|
538
|
+
*
|
|
539
|
+
* Should not be called if the whole workset is already locked.
|
|
540
|
+
*
|
|
541
|
+
* If `instancesToLock` is provided, it will try to lock only those instances.
|
|
542
|
+
*/
|
|
543
|
+
public async tryLock(instancesToLock?: string[]): Promise<void> {
|
|
544
|
+
const [, lockedInstanceIds] = await this.instanceLockService.tryLockInstances(
|
|
545
|
+
this.project.id,
|
|
546
|
+
instancesToLock ?? Array.from(this.instanceIdsToLockIds),
|
|
547
|
+
{
|
|
548
|
+
title: "Operation Lock",
|
|
549
|
+
description: `The instance is locked for the ${this.operation.type} operation with ID "${this.operation.id}".`,
|
|
550
|
+
icon: "mdi:cog-sync",
|
|
551
|
+
},
|
|
552
|
+
{ type: "operation", operationId: this.operation.id },
|
|
553
|
+
true, // allow partial locking
|
|
554
|
+
)
|
|
555
|
+
|
|
556
|
+
// add locked instance IDs to the workset and remove them from the instanceIdsToLockIds
|
|
557
|
+
for (const instanceId of lockedInstanceIds) {
|
|
558
|
+
this.lockedInstanceIds.add(instanceId)
|
|
559
|
+
this.instanceIdsToLockIds.delete(instanceId)
|
|
560
|
+
this.lockEventEmitter.emit(instanceId, null)
|
|
561
|
+
}
|
|
482
562
|
}
|
|
483
563
|
|
|
484
564
|
public static async load(
|
|
485
|
-
|
|
565
|
+
project: Project,
|
|
566
|
+
operation: Operation,
|
|
486
567
|
projectBackend: ProjectBackend,
|
|
487
568
|
libraryBackend: LibraryBackend,
|
|
488
|
-
stateBackend: StateBackend,
|
|
489
569
|
stateManager: StateManager,
|
|
570
|
+
instanceLockService: InstanceLockService,
|
|
571
|
+
instanceStateService: InstanceStateService,
|
|
490
572
|
logger: Logger,
|
|
491
573
|
signal: AbortSignal,
|
|
492
574
|
): Promise<OperationWorkset> {
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
575
|
+
// TODO: use hotstate for virtual instances
|
|
576
|
+
const [library, { instances, hubs }, virtualInstances, states] = await Promise.all([
|
|
577
|
+
libraryBackend.loadLibrary(project.libraryId, signal),
|
|
578
|
+
projectBackend.getProjectModel(project, signal),
|
|
579
|
+
stateManager.getVirtualInstanceRepository(project.id).getAllItems(),
|
|
580
|
+
instanceStateService.getInstanceStates(project.id),
|
|
498
581
|
])
|
|
499
582
|
|
|
500
583
|
const workset = new OperationWorkset(
|
|
584
|
+
project,
|
|
501
585
|
operation,
|
|
502
586
|
library,
|
|
503
|
-
|
|
587
|
+
instanceLockService,
|
|
588
|
+
instanceStateService,
|
|
504
589
|
logger.child({ operationId: operation.id, service: "OperationWorkset" }),
|
|
505
590
|
)
|
|
506
591
|
|
|
507
592
|
// prepare instances
|
|
508
|
-
for (const instance of
|
|
593
|
+
for (const instance of instances) {
|
|
509
594
|
workset.addInstance(instance)
|
|
510
595
|
}
|
|
511
596
|
|
|
512
|
-
for (const instance of
|
|
513
|
-
const worksetInstance = workset.instanceMap.get(instance.
|
|
597
|
+
for (const instance of virtualInstances) {
|
|
598
|
+
const worksetInstance = workset.instanceMap.get(instance.id)
|
|
514
599
|
|
|
515
600
|
if (worksetInstance) {
|
|
516
|
-
worksetInstance.outputs = instance.
|
|
517
|
-
worksetInstance.resolvedOutputs = instance.
|
|
518
|
-
} else if (instance.
|
|
519
|
-
workset.addInstance(instance
|
|
601
|
+
worksetInstance.outputs = instance.outputs
|
|
602
|
+
worksetInstance.resolvedOutputs = instance.resolvedOutputs
|
|
603
|
+
} else if (instance.parentId) {
|
|
604
|
+
workset.addInstance(instance)
|
|
520
605
|
} else {
|
|
521
606
|
workset.logger.warn(
|
|
522
|
-
`ignoring instance "${instance.
|
|
607
|
+
`ignoring virtual instance "${instance.id}" because it is not in the project or is not a part of known composite instance`,
|
|
523
608
|
)
|
|
524
609
|
continue
|
|
525
610
|
}
|
|
526
|
-
|
|
527
|
-
for (const child of instance.children) {
|
|
528
|
-
if (!workset.instanceMap.has(child.id)) {
|
|
529
|
-
workset.addInstance(child)
|
|
530
|
-
}
|
|
531
|
-
}
|
|
532
611
|
}
|
|
533
612
|
|
|
534
613
|
const unitSources = await libraryBackend.getResolvedUnitSources(
|
|
535
|
-
|
|
614
|
+
project.libraryId,
|
|
615
|
+
unique(Array.from(workset.instanceMap.values()).map(i => i.type)),
|
|
536
616
|
)
|
|
537
617
|
|
|
538
618
|
for (const unitSource of unitSources) {
|
|
@@ -559,7 +639,7 @@ export class OperationWorkset {
|
|
|
559
639
|
})
|
|
560
640
|
}
|
|
561
641
|
|
|
562
|
-
for (const hub of
|
|
642
|
+
for (const hub of hubs) {
|
|
563
643
|
workset.inputResolverNodes.set(`hub:${hub.id}`, { kind: "hub", hub })
|
|
564
644
|
}
|
|
565
645
|
|
|
@@ -600,6 +680,14 @@ export class OperationWorkset {
|
|
|
600
680
|
|
|
601
681
|
workset.calculateInstanceIdsToDestroy()
|
|
602
682
|
|
|
683
|
+
for (const instanceId of workset.instanceIdsToUpdate) {
|
|
684
|
+
workset.instanceIdsToLockIds.add(instanceId)
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
for (const instanceId of workset.instanceIdsToDestroy) {
|
|
688
|
+
workset.instanceIdsToLockIds.add(instanceId)
|
|
689
|
+
}
|
|
690
|
+
|
|
603
691
|
return workset
|
|
604
692
|
}
|
|
605
693
|
}
|