@highstate/backend 0.9.9 → 0.9.10
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-NMGIUI6X.js → chunk-DQDXRDUA.js} +228 -96
- package/dist/chunk-DQDXRDUA.js.map +1 -0
- package/dist/{chunk-EQ4LMS7B.js → chunk-WXDYCRTT.js} +1 -57
- package/dist/chunk-WXDYCRTT.js.map +1 -0
- package/dist/highstate.manifest.json +3 -3
- package/dist/index.js +100 -98
- package/dist/index.js.map +1 -1
- package/dist/library/worker/main.js +1 -1
- package/dist/shared/index.js +11 -13
- package/package.json +3 -3
- package/src/common/utils.ts +0 -74
- package/src/library/abstractions.ts +0 -5
- package/src/orchestrator/operation-workset.ts +47 -55
- package/src/orchestrator/operation.ts +1 -1
- package/src/project/manager.ts +66 -61
- package/src/shared/async-batcher.ts +73 -0
- package/src/shared/index.ts +1 -0
- package/src/shared/resolvers/graph-resolver.ts +146 -79
- package/src/shared/resolvers/input-hash.ts +22 -17
- package/src/shared/resolvers/input.ts +29 -26
- package/src/shared/resolvers/registry.ts +19 -9
- package/src/shared/resolvers/validation.ts +12 -18
- package/src/state/abstractions.ts +2 -3
- package/src/state/local.ts +13 -6
- package/src/terminal/manager.ts +2 -2
- package/dist/chunk-EQ4LMS7B.js.map +0 -1
- package/dist/chunk-NMGIUI6X.js.map +0 -1
@@ -43,61 +43,6 @@ function errorToString(error) {
|
|
43
43
|
}
|
44
44
|
return JSON.stringify(error);
|
45
45
|
}
|
46
|
-
function createAsyncBatcher(fn, { waitMs = 100, maxWaitTimeMs = 1e3 } = {}) {
|
47
|
-
let batch = [];
|
48
|
-
let activeTimeout = null;
|
49
|
-
let maxWaitTimeout = null;
|
50
|
-
let firstCallTimestamp = null;
|
51
|
-
async function processBatch() {
|
52
|
-
if (batch.length === 0) return;
|
53
|
-
const currentBatch = batch;
|
54
|
-
batch = [];
|
55
|
-
await fn(currentBatch);
|
56
|
-
if (maxWaitTimeout) {
|
57
|
-
clearTimeout(maxWaitTimeout);
|
58
|
-
maxWaitTimeout = null;
|
59
|
-
}
|
60
|
-
firstCallTimestamp = null;
|
61
|
-
}
|
62
|
-
function schedule() {
|
63
|
-
if (activeTimeout) clearTimeout(activeTimeout);
|
64
|
-
activeTimeout = setTimeout(() => {
|
65
|
-
activeTimeout = null;
|
66
|
-
void processBatch();
|
67
|
-
}, waitMs);
|
68
|
-
if (!firstCallTimestamp) {
|
69
|
-
firstCallTimestamp = Date.now();
|
70
|
-
maxWaitTimeout = setTimeout(() => {
|
71
|
-
if (activeTimeout) clearTimeout(activeTimeout);
|
72
|
-
activeTimeout = null;
|
73
|
-
void processBatch();
|
74
|
-
}, maxWaitTimeMs);
|
75
|
-
}
|
76
|
-
}
|
77
|
-
return {
|
78
|
-
/**
|
79
|
-
* Add an item to the batch.
|
80
|
-
*/
|
81
|
-
call(item) {
|
82
|
-
batch.push(item);
|
83
|
-
schedule();
|
84
|
-
},
|
85
|
-
/**
|
86
|
-
* Immediately flush the pending batch (if any).
|
87
|
-
*/
|
88
|
-
async flush() {
|
89
|
-
if (activeTimeout) {
|
90
|
-
clearTimeout(activeTimeout);
|
91
|
-
activeTimeout = null;
|
92
|
-
}
|
93
|
-
if (maxWaitTimeout) {
|
94
|
-
clearTimeout(maxWaitTimeout);
|
95
|
-
maxWaitTimeout = null;
|
96
|
-
}
|
97
|
-
await processBatch();
|
98
|
-
}
|
99
|
-
};
|
100
|
-
}
|
101
46
|
|
102
47
|
// src/common/pulumi.ts
|
103
48
|
import { BetterLock } from "better-lock";
|
@@ -280,11 +225,10 @@ export {
|
|
280
225
|
tryWrapAbortErrorLike,
|
281
226
|
stringArrayType,
|
282
227
|
errorToString,
|
283
|
-
createAsyncBatcher,
|
284
228
|
LocalPulumiHost,
|
285
229
|
valueToString,
|
286
230
|
stringToValue,
|
287
231
|
updateResourceCount,
|
288
232
|
resolveMainLocalProject
|
289
233
|
};
|
290
|
-
//# sourceMappingURL=chunk-
|
234
|
+
//# sourceMappingURL=chunk-WXDYCRTT.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"sources":["../src/common/utils.ts","../src/common/pulumi.ts","../src/common/local.ts"],"sourcesContent":["import { z } from \"zod\"\n\nexport async function runWithRetryOnError<T>(\n runner: () => T | Promise<T>,\n tryHandleError: (error: unknown) => boolean | Promise<boolean>,\n maxRetries: number = 1,\n): Promise<T> {\n let lastError: unknown\n\n for (let i = 0; i < maxRetries + 1; i++) {\n try {\n return await runner()\n } catch (e) {\n lastError = e\n\n if (await tryHandleError(e)) {\n continue\n }\n\n throw e\n }\n }\n\n throw lastError\n}\n\nexport class AbortError extends Error {\n constructor(options?: ErrorOptions) {\n super(\"Operation aborted\", options)\n }\n}\n\nexport function isAbortError(error: unknown): boolean {\n return error instanceof Error && error.name === \"AbortError\"\n}\n\nconst abortMessagePatterns = [\"Operation aborted\", \"Command was killed with SIGINT\"]\n\nexport function isAbortErrorLike(error: unknown): boolean {\n if (error instanceof Error) {\n return abortMessagePatterns.some(pattern => error.message.includes(pattern))\n }\n\n return false\n}\n\nexport function tryWrapAbortErrorLike(error: unknown): unknown {\n if (isAbortErrorLike(error)) {\n return new AbortError({ cause: error })\n }\n\n return error\n}\n\nexport const stringArrayType = z.string().transform(args => args.split(\",\").map(arg => arg.trim()))\n\nexport function errorToString(error: unknown): string {\n if (error instanceof Error) {\n return error.stack || error.message\n }\n\n return JSON.stringify(error)\n}\n","import type { ConfigMap, OpMap, OpType, Stack, WhoAmIResult } from \"@pulumi/pulumi/automation\"\nimport type { Logger } from \"pino\"\nimport { BetterLock } from \"better-lock\"\nimport { AbortError, runWithRetryOnError } from \"./utils\"\n\nexport type RunOptions = {\n projectId: string\n pulumiProjectName: string\n pulumiStackName: string\n envVars?: Record<string, string>\n}\n\nexport type RunLocalOptions = RunOptions & {\n projectPath: string\n stackConfig?: ConfigMap\n}\n\nexport class LocalPulumiHost {\n private lock = new BetterLock()\n\n private constructor(private readonly logger: Logger) {}\n\n async getCurrentUser(): Promise<WhoAmIResult | null> {\n const { LocalWorkspace } = await import(\"@pulumi/pulumi/automation/index.js\")\n const workspace = await LocalWorkspace.create({})\n\n try {\n return await workspace.whoAmI()\n } catch (error) {\n this.logger.error({ msg: \"failed to get current user\", error })\n\n return null\n }\n }\n\n async runEmpty<T>(\n options: RunOptions,\n fn: (stack: Stack) => Promise<T>,\n signal?: AbortSignal,\n ): Promise<T> {\n const { projectId, pulumiProjectName, pulumiStackName, envVars } = options\n\n return await this.lock.acquire(`${pulumiProjectName}.${pulumiStackName}`, async () => {\n const { LocalWorkspace } = await import(\"@pulumi/pulumi/automation/index.js\")\n\n const stack = await LocalWorkspace.createOrSelectStack(\n {\n projectName: pulumiProjectName,\n stackName: pulumiStackName,\n program: () => Promise.resolve(),\n },\n {\n projectSettings: {\n name: pulumiProjectName,\n runtime: \"nodejs\",\n },\n envVars: {\n PULUMI_CONFIG_PASSPHRASE: this.getPassword(projectId),\n PULUMI_K8S_AWAIT_ALL: \"true\",\n ...envVars,\n },\n },\n )\n\n signal?.throwIfAborted()\n\n try {\n return await runWithRetryOnError(\n () => fn(stack),\n error => this.tryUnlockStack(stack, error),\n )\n } catch (e) {\n if (e instanceof Error && e.message.includes(\"canceled\")) {\n throw new AbortError()\n }\n\n throw e\n }\n })\n }\n\n async runLocal<T>(\n options: RunLocalOptions,\n fn: (stack: Stack) => Promise<T>,\n signal?: AbortSignal,\n ): Promise<T> {\n const { projectId, pulumiProjectName, pulumiStackName, projectPath, stackConfig, envVars } =\n options\n\n return await this.lock.acquire(`${pulumiProjectName}.${pulumiStackName}`, async () => {\n const { LocalWorkspace } = await import(\"@pulumi/pulumi/automation/index.js\")\n\n const stack = await LocalWorkspace.createOrSelectStack(\n {\n stackName: pulumiStackName,\n workDir: projectPath,\n },\n {\n projectSettings: {\n name: pulumiProjectName,\n runtime: \"nodejs\",\n },\n stackSettings: stackConfig\n ? {\n [pulumiStackName]: {\n config: stackConfig,\n },\n }\n : undefined,\n envVars: {\n PULUMI_CONFIG_PASSPHRASE: this.getPassword(projectId),\n PULUMI_K8S_AWAIT_ALL: \"true\",\n ...envVars,\n },\n },\n )\n\n signal?.throwIfAborted()\n\n try {\n return await runWithRetryOnError(\n () => fn(stack),\n error => this.tryUnlockStack(stack, error),\n )\n } catch (e) {\n if (e instanceof Error && e.message.includes(\"canceled\")) {\n throw new AbortError()\n }\n\n throw e\n }\n })\n }\n\n private sharedPassword: string = process.env.PULUMI_CONFIG_PASSPHRASE ?? \"\"\n private passwords = new Map<string, string>()\n\n hasPassword(projectId: string) {\n return !!this.sharedPassword || this.passwords.has(projectId)\n }\n\n setPassword(projectId: string, password: string) {\n this.passwords.set(projectId, password)\n }\n\n removePassword(projectId: string) {\n this.passwords.delete(projectId)\n }\n\n private getPassword(projectId: string) {\n return this.sharedPassword || this.passwords.get(projectId) || \"\"\n }\n\n async tryUnlockStack(stack: Stack, error: unknown) {\n if (error instanceof Error && error.message.includes(\"the stack is currently locked\")) {\n // TODO: kill the process if the hostname matches the current hostname\n\n this.logger.warn({ stackName: stack.name }, \"inlocking stack\")\n await stack.cancel()\n return true\n }\n\n return false\n }\n\n static create(logger: Logger) {\n return new LocalPulumiHost(logger.child({ service: \"LocalPulumiHost\" }))\n }\n}\n\nexport function valueToString(value: unknown): string {\n if (typeof value === \"string\") {\n return value\n }\n\n return JSON.stringify(value)\n}\n\nexport function stringToValue(value: string): unknown {\n try {\n return JSON.parse(value)\n } catch {\n return value\n }\n}\n\nexport function updateResourceCount(opType: OpType, currentCount: number): number {\n switch (opType) {\n case \"same\":\n case \"create\":\n case \"update\":\n case \"replace\":\n case \"create-replacement\":\n case \"import\":\n case \"import-replacement\":\n return currentCount + 1\n\n case \"delete\":\n case \"delete-replaced\":\n case \"discard\":\n case \"discard-replaced\":\n case \"remove-pending-replace\":\n return currentCount - 1\n\n case \"refresh\":\n case \"read-replacement\":\n case \"read\":\n return currentCount\n\n default:\n throw new Error(`Unknown operation type: ${opType as string}`)\n }\n}\n\nexport function calculateTotalResources(opMap: OpMap | undefined): number {\n if (!opMap) {\n return 0 // No operations imply no resources\n }\n\n let total = 0\n\n for (const [op, count] of Object.entries(opMap)) {\n const opType = op as OpType\n const value = count ?? 0\n\n total = updateResourceCount(opType, value)\n }\n\n return total\n}\n","import { basename } from \"node:path\"\nimport { findWorkspaceDir, readPackageJSON } from \"pkg-types\"\n\nexport async function resolveMainLocalProject(\n projectPath?: string,\n projectName?: string,\n): Promise<[projecPath: string, projectName: string]> {\n if (!projectPath) {\n projectPath = await findWorkspaceDir()\n }\n\n if (!projectName) {\n const packageJson = await readPackageJSON(projectPath)\n projectName = packageJson.name\n }\n\n if (!projectName) {\n projectName = basename(projectPath)\n }\n\n return [projectPath, projectName]\n}\n"],"mappings":"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","names":[]}
|
@@ -1,8 +1,8 @@
|
|
1
1
|
{
|
2
2
|
"sourceHashes": {
|
3
|
-
"./dist/index.js": "
|
4
|
-
"./dist/shared/index.js": "
|
5
|
-
"./dist/library/worker/main.js": "
|
3
|
+
"./dist/index.js": "65eb8a0ed4774e1bbd2a2a6176b0840b2fec9c515a620b90a963900a3cd5e155",
|
4
|
+
"./dist/shared/index.js": "0d314d61379d99c55057d507979d2f49119b0da831fbbc8681fccf05d99a4d5c",
|
5
|
+
"./dist/library/worker/main.js": "4e24e61811d3f605da65f70dc14cd2585f551e28773d96686cc188e66fe57650",
|
6
6
|
"./dist/library/package-resolution-worker.js": "4bfa368ad35a64c109df9e5a468c057791164760fe166c4eb5d9a889dee4d7bc"
|
7
7
|
}
|
8
8
|
}
|
package/dist/index.js
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
import {
|
2
|
+
InputHashResolver,
|
3
|
+
InputResolver,
|
2
4
|
applyPartialInstanceState,
|
3
5
|
compositeInstanceSchema,
|
4
|
-
|
5
|
-
createInputResolver,
|
6
|
+
createAsyncBatcher,
|
6
7
|
createInstanceState,
|
7
8
|
createInstanceStatePatch,
|
8
9
|
diffLibraries,
|
@@ -17,10 +18,9 @@ import {
|
|
17
18
|
isFinalOperationStatus,
|
18
19
|
projectOperationSchema,
|
19
20
|
terminalSessionSchema
|
20
|
-
} from "./chunk-
|
21
|
+
} from "./chunk-DQDXRDUA.js";
|
21
22
|
import {
|
22
23
|
LocalPulumiHost,
|
23
|
-
createAsyncBatcher,
|
24
24
|
errorToString,
|
25
25
|
isAbortError,
|
26
26
|
isAbortErrorLike,
|
@@ -31,7 +31,7 @@ import {
|
|
31
31
|
tryWrapAbortErrorLike,
|
32
32
|
updateResourceCount,
|
33
33
|
valueToString
|
34
|
-
} from "./chunk-
|
34
|
+
} from "./chunk-WXDYCRTT.js";
|
35
35
|
|
36
36
|
// src/secret/abstractions.ts
|
37
37
|
var SecretAccessDeniedError = class extends Error {
|
@@ -950,17 +950,17 @@ var ProjectManager = class _ProjectManager {
|
|
950
950
|
}
|
951
951
|
async createInstance(projectId, instance) {
|
952
952
|
const createdInstance = await this.projectBackend.createInstance(projectId, instance);
|
953
|
-
await this.
|
953
|
+
await this.evaluateChangedCompositeInstances(projectId);
|
954
954
|
return createdInstance;
|
955
955
|
}
|
956
956
|
async updateInstance(projectId, instanceId, patch) {
|
957
957
|
const instance = await this.projectBackend.updateInstance(projectId, instanceId, patch);
|
958
|
-
await this.
|
958
|
+
await this.evaluateChangedCompositeInstances(projectId);
|
959
959
|
return instance;
|
960
960
|
}
|
961
961
|
async renameInstance(projectId, instanceId, newName) {
|
962
962
|
const instance = await this.projectBackend.renameInstance(projectId, instanceId, newName);
|
963
|
-
await this.
|
963
|
+
await this.evaluateChangedCompositeInstances(projectId);
|
964
964
|
return instance;
|
965
965
|
}
|
966
966
|
async deleteInstance(projectId, instanceId) {
|
@@ -969,40 +969,27 @@ var ProjectManager = class _ProjectManager {
|
|
969
969
|
this.stateBackend.clearCompositeInstances(projectId, [instanceId])
|
970
970
|
]);
|
971
971
|
}
|
972
|
-
async
|
973
|
-
const {
|
974
|
-
|
975
|
-
|
976
|
-
|
977
|
-
|
978
|
-
|
979
|
-
return;
|
980
|
-
}
|
981
|
-
const { inputHash: expectedInputHash } = await resolveInputHash(instance.id);
|
982
|
-
const inputHash = await this.stateBackend.getCompositeInstanceInputHash(projectId, instance.id);
|
983
|
-
if (inputHash !== expectedInputHash) {
|
984
|
-
this.logger.info("re-evaluating instance since input hash has changed", {
|
985
|
-
projectId,
|
986
|
-
instanceId: instance.id
|
987
|
-
});
|
988
|
-
await this.evaluateCompositeInstances(projectId, [instance.id]);
|
989
|
-
}
|
990
|
-
}
|
991
|
-
async evaluateCompositeInstances(projectId, instanceIds) {
|
972
|
+
async evaluateChangedCompositeInstances(projectId) {
|
973
|
+
const { inputHashResolver, instances, library, evaluatedInputHashes } = await this.prepareResolvers(projectId);
|
974
|
+
inputHashResolver.addAllNodesToWorkset();
|
975
|
+
await inputHashResolver.process();
|
976
|
+
const instanceIds = instances.filter((instance) => !isUnitModel2(library.components[instance.type])).filter(
|
977
|
+
(instance) => evaluatedInputHashes[instance.id] !== inputHashResolver.requireOutput(instance.id).inputHash
|
978
|
+
).map((instance) => instance.id);
|
992
979
|
await this.projectLockManager.getLock(projectId).lockInstances(instanceIds, async () => {
|
993
980
|
this.logger.debug({ instanceIds }, "evaluating composite instances");
|
994
981
|
for (const instanceId of instanceIds) {
|
995
982
|
this.compositeInstanceEE.emit(projectId, { type: "evaluation-started", instanceId });
|
996
983
|
}
|
997
984
|
const [
|
998
|
-
{ instances, resolvedInputs, stateMap,
|
985
|
+
{ instances: instances2, resolvedInputs, stateMap, inputHashResolver: inputHashResolver2 },
|
999
986
|
topLevelCompositeChildrenIds
|
1000
987
|
] = await Promise.all([
|
1001
|
-
this.
|
988
|
+
this.prepareResolvers(projectId),
|
1002
989
|
this.stateBackend.getTopLevelCompositeChildrenIds(projectId, instanceIds)
|
1003
990
|
]);
|
1004
991
|
const results = await this.libraryBackend.evaluateCompositeInstances(
|
1005
|
-
|
992
|
+
instances2,
|
1006
993
|
resolvedInputs,
|
1007
994
|
instanceIds
|
1008
995
|
);
|
@@ -1012,15 +999,15 @@ var ProjectManager = class _ProjectManager {
|
|
1012
999
|
newState.evaluationError = result.success ? null : result.error;
|
1013
1000
|
return newState;
|
1014
1001
|
});
|
1015
|
-
|
1016
|
-
|
1017
|
-
const { inputHash } = await resolveInputHash(instanceId);
|
1018
|
-
inputHashes.set(instanceId, inputHash);
|
1019
|
-
}
|
1002
|
+
inputHashResolver2.addAllNodesToWorkset();
|
1003
|
+
await inputHashResolver2.process();
|
1020
1004
|
const compositeInstances = results.filter((result) => result.success).flatMap(
|
1021
1005
|
(result) => result.compositeInstances.map((instance) => ({
|
1022
1006
|
...instance,
|
1023
|
-
inputHash:
|
1007
|
+
inputHash: (
|
1008
|
+
// only store inputHash for top-level composite instances
|
1009
|
+
instance.instance.id === result.instanceId ? inputHashResolver2.requireOutput(instance.instance.id).inputHash : ""
|
1010
|
+
)
|
1024
1011
|
}))
|
1025
1012
|
);
|
1026
1013
|
const newTopLevelCompositeChildrenIds = Object.fromEntries(
|
@@ -1047,6 +1034,16 @@ var ProjectManager = class _ProjectManager {
|
|
1047
1034
|
]);
|
1048
1035
|
for (const state of newStates) {
|
1049
1036
|
this.stateManager.emitStatePatch(projectId, state);
|
1037
|
+
if (state.evaluationError) {
|
1038
|
+
this.logger.error(
|
1039
|
+
{ projectId, instanceId: state.id, error: state.evaluationError },
|
1040
|
+
"instance evaluation failed"
|
1041
|
+
);
|
1042
|
+
this.compositeInstanceEE.emit(projectId, {
|
1043
|
+
type: "failed",
|
1044
|
+
instanceId: state.id
|
1045
|
+
});
|
1046
|
+
}
|
1050
1047
|
}
|
1051
1048
|
for (const instance of compositeInstances) {
|
1052
1049
|
this.compositeInstanceEE.emit(projectId, { type: "updated", instance });
|
@@ -1073,11 +1070,14 @@ var ProjectManager = class _ProjectManager {
|
|
1073
1070
|
await Promise.all(promises);
|
1074
1071
|
});
|
1075
1072
|
}
|
1076
|
-
async
|
1077
|
-
const { instances, hubs } = await
|
1078
|
-
|
1073
|
+
async prepareResolvers(projectId) {
|
1074
|
+
const [{ instances, hubs }, states, library, evaluatedInputHashes] = await Promise.all([
|
1075
|
+
this.projectBackend.getProject(projectId),
|
1076
|
+
this.stateBackend.getAllInstanceStates(projectId),
|
1077
|
+
this.libraryBackend.loadLibrary(),
|
1078
|
+
this.stateBackend.getCompositeInstanceInputHashes(projectId)
|
1079
|
+
]);
|
1079
1080
|
const filteredInstances = instances.filter((instance) => instance.type in library.components);
|
1080
|
-
const states = await this.stateBackend.getAllInstanceStates(projectId);
|
1081
1081
|
const stateMap = new Map(states.map((state) => [state.id, state]));
|
1082
1082
|
const inputResolverNodes = /* @__PURE__ */ new Map();
|
1083
1083
|
for (const instance of filteredInstances) {
|
@@ -1090,11 +1090,13 @@ var ProjectManager = class _ProjectManager {
|
|
1090
1090
|
for (const hub of hubs) {
|
1091
1091
|
inputResolverNodes.set(`hub:${hub.id}`, { kind: "hub", hub });
|
1092
1092
|
}
|
1093
|
-
const
|
1093
|
+
const inputResolver = new InputResolver(inputResolverNodes, this.logger);
|
1094
|
+
inputResolver.addAllNodesToWorkset();
|
1094
1095
|
const inputHashInputs = /* @__PURE__ */ new Map();
|
1095
1096
|
const resolvedInputs = {};
|
1097
|
+
await inputResolver.process();
|
1096
1098
|
for (const instance of filteredInstances) {
|
1097
|
-
const output =
|
1099
|
+
const output = inputResolver.requireOutput(`instance:${instance.id}`);
|
1098
1100
|
if (output.kind !== "instance") {
|
1099
1101
|
throw new Error("Expected instance node");
|
1100
1102
|
}
|
@@ -1118,13 +1120,15 @@ var ProjectManager = class _ProjectManager {
|
|
1118
1120
|
});
|
1119
1121
|
resolvedInputs[instance.id] = output.resolvedInputs;
|
1120
1122
|
}
|
1121
|
-
const
|
1123
|
+
const inputHashResolver = new InputHashResolver(inputHashInputs, this.logger);
|
1122
1124
|
return {
|
1123
|
-
|
1125
|
+
inputHashInputs,
|
1126
|
+
inputHashResolver,
|
1124
1127
|
library,
|
1125
|
-
instances,
|
1128
|
+
instances: filteredInstances,
|
1126
1129
|
stateMap,
|
1127
|
-
resolvedInputs
|
1130
|
+
resolvedInputs,
|
1131
|
+
evaluatedInputHashes
|
1128
1132
|
};
|
1129
1133
|
}
|
1130
1134
|
async watchLibraryChanges() {
|
@@ -1158,7 +1162,7 @@ var ProjectManager = class _ProjectManager {
|
|
1158
1162
|
);
|
1159
1163
|
const projects = await this.projectBackend.getProjectIds();
|
1160
1164
|
for (const projectId of projects) {
|
1161
|
-
const {
|
1165
|
+
const { instances } = await this.prepareResolvers(projectId);
|
1162
1166
|
const filteredInstances = instances.filter(
|
1163
1167
|
(instance) => changedComponents.has(instance.type) && library.components[instance.type] && !isUnitModel2(library.components[instance.type])
|
1164
1168
|
);
|
@@ -1166,16 +1170,8 @@ var ProjectManager = class _ProjectManager {
|
|
1166
1170
|
{ projectId, filteredInstanceIds: filteredInstances.map((instance) => instance.id) },
|
1167
1171
|
"updating composite instances for project"
|
1168
1172
|
);
|
1169
|
-
const inputHashMap = /* @__PURE__ */ new Map();
|
1170
|
-
for (const instance of filteredInstances) {
|
1171
|
-
const { inputHash } = await resolveInputHash(instance.id);
|
1172
|
-
inputHashMap.set(instance.id, inputHash);
|
1173
|
-
}
|
1174
1173
|
try {
|
1175
|
-
await this.
|
1176
|
-
projectId,
|
1177
|
-
filteredInstances.map((instance) => instance.id)
|
1178
|
-
);
|
1174
|
+
await this.evaluateChangedCompositeInstances(projectId);
|
1179
1175
|
} catch (error) {
|
1180
1176
|
this.logger.error({ error }, "failed to evaluate composite instances");
|
1181
1177
|
}
|
@@ -2296,10 +2292,13 @@ var LocalStateBackend = class _LocalStateBackend {
|
|
2296
2292
|
const sublevel = this.getProjectCompositeInstancesSublevel(projectId);
|
2297
2293
|
return this.getSublevelItem(sublevel, compositeInstanceSchema, instanceId);
|
2298
2294
|
}
|
2299
|
-
async
|
2295
|
+
async getCompositeInstanceInputHashes(projectId) {
|
2300
2296
|
const sublevel = this.getProjectCompositeInstanceInputHashesSublevel(projectId);
|
2301
|
-
const
|
2302
|
-
|
2297
|
+
const result = {};
|
2298
|
+
for await (const [key, value] of sublevel.iterator()) {
|
2299
|
+
result[key] = value;
|
2300
|
+
}
|
2301
|
+
return result;
|
2303
2302
|
}
|
2304
2303
|
async putCompositeInstances(projectId, instances) {
|
2305
2304
|
this.validateArray(compositeInstanceSchema, instances);
|
@@ -2312,6 +2311,12 @@ var LocalStateBackend = class _LocalStateBackend {
|
|
2312
2311
|
key: instance.instance.id,
|
2313
2312
|
value: compositeInstanceSchema.parse(instance),
|
2314
2313
|
sublevel
|
2314
|
+
},
|
2315
|
+
{
|
2316
|
+
type: "put",
|
2317
|
+
key: instance.instance.id,
|
2318
|
+
value: instance.inputHash ?? "",
|
2319
|
+
sublevel: inputHashesSublevel
|
2315
2320
|
}
|
2316
2321
|
])
|
2317
2322
|
);
|
@@ -2687,6 +2692,7 @@ import {
|
|
2687
2692
|
parseInstanceId as parseInstanceId2
|
2688
2693
|
} from "@highstate/contract";
|
2689
2694
|
import { unique as unique2 } from "remeda";
|
2695
|
+
import { BetterLock as BetterLock3 } from "better-lock";
|
2690
2696
|
var OperationWorkset = class _OperationWorkset {
|
2691
2697
|
constructor(operation, library, stateManager, logger) {
|
2692
2698
|
this.operation = operation;
|
@@ -2704,11 +2710,10 @@ var OperationWorkset = class _OperationWorkset {
|
|
2704
2710
|
stateChildIdMap = /* @__PURE__ */ new Map();
|
2705
2711
|
unitSourceHashMap = /* @__PURE__ */ new Map();
|
2706
2712
|
inputResolver;
|
2707
|
-
|
2708
|
-
inputResolverPromiseCache = /* @__PURE__ */ new Map();
|
2713
|
+
inputResolverNodes = /* @__PURE__ */ new Map();
|
2709
2714
|
inputHashResolver;
|
2710
|
-
|
2711
|
-
|
2715
|
+
inputHashNodes = /* @__PURE__ */ new Map();
|
2716
|
+
inputHashResolverLock = new BetterLock3();
|
2712
2717
|
resolvedInstanceInputs = /* @__PURE__ */ new Map();
|
2713
2718
|
getInstance(instanceId) {
|
2714
2719
|
const instance = this.instanceMap.get(instanceId);
|
@@ -2874,7 +2879,7 @@ var OperationWorkset = class _OperationWorkset {
|
|
2874
2879
|
}
|
2875
2880
|
}
|
2876
2881
|
const state = this.stateMap.get(instance.id);
|
2877
|
-
const { inputHash: expectedInputHash } =
|
2882
|
+
const { inputHash: expectedInputHash } = this.inputHashResolver.requireOutput(instance.id);
|
2878
2883
|
if (this.operation.options.forceUpdateDependencies) {
|
2879
2884
|
this.instanceIdsToUpdate.add(instanceId);
|
2880
2885
|
return;
|
@@ -2900,7 +2905,7 @@ var OperationWorkset = class _OperationWorkset {
|
|
2900
2905
|
continue;
|
2901
2906
|
}
|
2902
2907
|
const state = this.stateMap.get(child.id);
|
2903
|
-
const { inputHash: expectedInputHash } =
|
2908
|
+
const { inputHash: expectedInputHash } = this.inputHashResolver.requireOutput(child.id);
|
2904
2909
|
if (state?.status !== "created" || state.inputHash !== expectedInputHash) {
|
2905
2910
|
this.instanceIdsToUpdate.add(child.id);
|
2906
2911
|
}
|
@@ -2995,17 +3000,20 @@ var OperationWorkset = class _OperationWorkset {
|
|
2995
3000
|
}
|
2996
3001
|
}
|
2997
3002
|
async getUpToDateInputHash(instance) {
|
2998
|
-
|
2999
|
-
|
3000
|
-
instance,
|
3001
|
-
|
3002
|
-
|
3003
|
-
|
3004
|
-
|
3003
|
+
return await this.inputHashResolverLock.acquire(async () => {
|
3004
|
+
const component = this.library.components[instance.type];
|
3005
|
+
this.inputHashNodes.set(instance.id, {
|
3006
|
+
instance,
|
3007
|
+
component,
|
3008
|
+
resolvedInputs: this.resolvedInstanceInputs.get(instance.id),
|
3009
|
+
state: this.stateMap.get(instance.id),
|
3010
|
+
sourceHash: this.getSourceHashIfApplicable(instance, component)
|
3011
|
+
});
|
3012
|
+
this.inputHashResolver.invalidate(instance.id);
|
3013
|
+
await this.inputHashResolver.process();
|
3014
|
+
const { inputHash } = this.inputHashResolver.requireOutput(instance.id);
|
3015
|
+
return inputHash;
|
3005
3016
|
});
|
3006
|
-
this.inputHashResolverPromiseCache.delete(instance.id);
|
3007
|
-
const { inputHash } = await this.inputHashResolver(instance.id);
|
3008
|
-
return inputHash;
|
3009
3017
|
}
|
3010
3018
|
getLockInstanceIds() {
|
3011
3019
|
return Array.from(this.instanceIdsToUpdate.union(this.instanceIdsToDestroy));
|
@@ -3017,18 +3025,12 @@ var OperationWorkset = class _OperationWorkset {
|
|
3017
3025
|
stateBackend.getCompositeInstances(operation.projectId, signal),
|
3018
3026
|
stateBackend.getAllInstanceStates(operation.projectId, signal)
|
3019
3027
|
]);
|
3020
|
-
const unitSources = await libraryBackend.getResolvedUnitSources(
|
3021
|
-
unique2(project.instances.map((i) => i.type))
|
3022
|
-
);
|
3023
3028
|
const workset = new _OperationWorkset(
|
3024
3029
|
operation,
|
3025
3030
|
library,
|
3026
3031
|
stateManager,
|
3027
3032
|
logger.child({ operationId: operation.id, service: "OperationWorkset" })
|
3028
3033
|
);
|
3029
|
-
for (const unitSource of unitSources) {
|
3030
|
-
workset.unitSourceHashMap.set(unitSource.unitType, unitSource.sourceHash);
|
3031
|
-
}
|
3032
3034
|
for (const instance of project.instances) {
|
3033
3035
|
workset.addInstance(instance);
|
3034
3036
|
}
|
@@ -3051,6 +3053,12 @@ var OperationWorkset = class _OperationWorkset {
|
|
3051
3053
|
}
|
3052
3054
|
}
|
3053
3055
|
}
|
3056
|
+
const unitSources = await libraryBackend.getResolvedUnitSources(
|
3057
|
+
unique2(Array.from(workset.instanceMap.values().map((i) => i.type)))
|
3058
|
+
);
|
3059
|
+
for (const unitSource of unitSources) {
|
3060
|
+
workset.unitSourceHashMap.set(unitSource.unitType, unitSource.sourceHash);
|
3061
|
+
}
|
3054
3062
|
for (const state of states) {
|
3055
3063
|
if (!workset.instanceMap.has(state.id)) {
|
3056
3064
|
workset.logger.warn(
|
@@ -3061,29 +3069,26 @@ var OperationWorkset = class _OperationWorkset {
|
|
3061
3069
|
workset.setState(state);
|
3062
3070
|
}
|
3063
3071
|
for (const instance of workset.instanceMap.values()) {
|
3064
|
-
workset.
|
3072
|
+
workset.inputResolverNodes.set(`instance:${instance.id}`, {
|
3065
3073
|
kind: "instance",
|
3066
3074
|
instance,
|
3067
3075
|
component: library.components[instance.type]
|
3068
3076
|
});
|
3069
3077
|
}
|
3070
3078
|
for (const hub of project.hubs) {
|
3071
|
-
workset.
|
3079
|
+
workset.inputResolverNodes.set(`hub:${hub.id}`, { kind: "hub", hub });
|
3072
3080
|
}
|
3073
|
-
workset.inputResolver =
|
3074
|
-
|
3075
|
-
|
3076
|
-
logger,
|
3077
|
-
{ promiseCache: workset.inputResolverPromiseCache }
|
3078
|
-
);
|
3081
|
+
workset.inputResolver = new InputResolver(workset.inputResolverNodes, logger);
|
3082
|
+
workset.inputResolver.addAllNodesToWorkset();
|
3083
|
+
await workset.inputResolver.process();
|
3079
3084
|
for (const instance of workset.instanceMap.values()) {
|
3080
|
-
const output =
|
3085
|
+
const output = workset.inputResolver.requireOutput(`instance:${instance.id}`);
|
3081
3086
|
if (output.kind !== "instance") {
|
3082
3087
|
throw new Error("Unexpected output kind");
|
3083
3088
|
}
|
3084
3089
|
workset.resolvedInstanceInputs.set(instance.id, output.resolvedInputs);
|
3085
3090
|
const component = workset.library.components[instance.type];
|
3086
|
-
workset.
|
3091
|
+
workset.inputHashNodes.set(instance.id, {
|
3087
3092
|
instance,
|
3088
3093
|
component,
|
3089
3094
|
resolvedInputs: output.resolvedInputs,
|
@@ -3091,12 +3096,9 @@ var OperationWorkset = class _OperationWorkset {
|
|
3091
3096
|
sourceHash: workset.getSourceHashIfApplicable(instance, component)
|
3092
3097
|
});
|
3093
3098
|
}
|
3094
|
-
workset.inputHashResolver =
|
3095
|
-
|
3096
|
-
|
3097
|
-
logger,
|
3098
|
-
{ promiseCache: workset.inputHashResolverPromiseCache }
|
3099
|
-
);
|
3099
|
+
workset.inputHashResolver = new InputHashResolver(workset.inputHashNodes, logger);
|
3100
|
+
workset.inputHashResolver.addAllNodesToWorkset();
|
3101
|
+
await workset.inputHashResolver.process();
|
3100
3102
|
if (operation.type !== "destroy") {
|
3101
3103
|
await workset.calculateInstanceIdsToUpdate();
|
3102
3104
|
}
|