@highstate/backend 0.9.16 → 0.9.19
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-5WVU2AK4.js +1535 -0
- package/dist/chunk-5WVU2AK4.js.map +1 -0
- package/dist/chunk-I7BWSAN6.js +49 -0
- package/dist/chunk-I7BWSAN6.js.map +1 -0
- package/dist/{chunk-RCB4AFGD.js → chunk-VB4YL327.js} +51 -71
- package/dist/chunk-VB4YL327.js.map +1 -0
- package/dist/database/local/prisma.config.js +26 -0
- package/dist/database/local/prisma.config.js.map +1 -0
- package/dist/highstate.manifest.json +5 -4
- package/dist/index.js +7676 -6634
- package/dist/index.js.map +1 -1
- package/dist/library/package-resolution-worker.js +8 -6
- package/dist/library/package-resolution-worker.js.map +1 -1
- package/dist/library/worker/main.js +63 -58
- package/dist/library/worker/main.js.map +1 -1
- package/dist/shared/index.js +3 -216
- package/dist/shared/index.js.map +1 -1
- package/package.json +23 -11
- package/prisma/backend/_schema/layout.prisma +7 -0
- package/prisma/backend/_schema/library.prisma +17 -0
- package/prisma/backend/_schema/project.prisma +101 -0
- package/prisma/backend/_schema/pulumi.prisma +17 -0
- package/prisma/backend/postgresql/main.prisma +17 -0
- package/prisma/backend/sqlite/main.prisma +17 -0
- package/prisma/backend/sqlite/migrations/20250817070609_initiial/migration.sql +34 -0
- package/prisma/backend/sqlite/migrations/20250817104948_add_fields/migration.sql +59 -0
- package/prisma/backend/sqlite/migrations/20250818082732_add_models/migration.sql +41 -0
- package/prisma/backend/sqlite/migrations/20250818083106_a/migration.sql +19 -0
- package/prisma/backend/sqlite/migrations/20250818101945_hi/migration.sql +1 -0
- package/prisma/backend/sqlite/migrations/20250819082315_a/migration.sql +5 -0
- package/prisma/backend/sqlite/migrations/migration_lock.toml +3 -0
- package/prisma/project/api-key.prisma +27 -0
- package/prisma/project/artifact.prisma +52 -0
- package/prisma/project/custom-status.prisma +46 -0
- package/prisma/project/evaluation.prisma +35 -0
- package/prisma/project/instance.prisma +160 -0
- package/prisma/project/layout.prisma +23 -0
- package/prisma/project/lock.prisma +18 -0
- package/prisma/project/main.prisma +17 -0
- package/prisma/project/migrations/20250816081310_initial/migration.sql +300 -0
- package/prisma/project/migrations/20250816082523_test/migration.sql +72 -0
- package/prisma/project/migrations/20250818065643_update/migration.sql +42 -0
- package/prisma/project/migrations/20250818070758_a/migration.sql +8 -0
- package/prisma/project/migrations/20250818070913_a/migration.sql +8 -0
- package/prisma/project/migrations/20250818082720_add_motels/migration.sql +11 -0
- package/prisma/project/migrations/20250818112523_hello/migration.sql +35 -0
- package/prisma/project/migrations/20250819082305_a/migration.sql +14 -0
- package/prisma/project/migrations/20250819165004_add_missing_fields/migration.sql +216 -0
- package/prisma/project/migrations/20250819171309_a/migration.sql +22 -0
- package/prisma/project/migrations/20250820113949_a/migration.sql +66 -0
- package/prisma/project/migrations/20250820144256_b/migration.sql +31 -0
- package/prisma/project/migrations/20250820145547_a/migration.sql +24 -0
- package/prisma/project/migrations/20250820182517_b/migration.sql +2 -0
- package/prisma/project/migrations/20250821172324_a/migration.sql +2 -0
- package/prisma/project/migrations/20250822081339_a/migration.sql +219 -0
- package/prisma/project/migrations/20250822083742_b/migration.sql +1 -0
- package/prisma/project/migrations/20250822105134_boom/migration.sql +1 -0
- package/prisma/project/migrations/20250822141028_b/migration.sql +1 -0
- package/prisma/project/migrations/20250822142342_b/migration.sql +16 -0
- package/prisma/project/migrations/20250824072720_a/migration.sql +1 -0
- package/prisma/project/migrations/20250824093656_b/migration.sql +21 -0
- package/prisma/project/migrations/20250825082518_a/migration.sql +1 -0
- package/prisma/project/migrations/20250825085343_b/migration.sql +1 -0
- package/prisma/project/migrations/20250825091312_a/migration.sql +1 -0
- package/prisma/project/migrations/20250903095431_hi/migration.sql +44 -0
- package/prisma/project/migrations/20250903174255_a/migration.sql +24 -0
- package/prisma/project/migrations/20250908095205_hi/migration.sql +18 -0
- package/prisma/project/migrations/20250909155857_hi/migration.sql +15 -0
- package/prisma/project/migrations/migration_lock.toml +3 -0
- package/prisma/project/model.prisma +37 -0
- package/prisma/project/operation.prisma +148 -0
- package/prisma/project/page.prisma +41 -0
- package/prisma/project/secret.prisma +42 -0
- package/prisma/project/service-account.prisma +36 -0
- package/prisma/project/terminal.prisma +90 -0
- package/prisma/project/trigger.prisma +31 -0
- package/prisma/project/unlock-method.prisma +32 -0
- package/prisma/project/worker.prisma +138 -0
- package/src/artifact/abstractions.ts +13 -13
- package/src/artifact/encryption.ts +31 -15
- package/src/artifact/factory.ts +7 -10
- package/src/artifact/local.ts +33 -50
- package/src/business/api-key.ts +24 -36
- package/src/business/artifact.test.ts +978 -0
- package/src/business/artifact.ts +136 -215
- package/src/business/evaluation.ts +328 -0
- package/src/business/index.ts +5 -1
- package/src/business/instance-lock.test.ts +1060 -0
- package/src/business/instance-lock.ts +387 -77
- package/src/business/instance-state.test.ts +735 -0
- package/src/business/instance-state.ts +604 -217
- package/src/business/operation.test.ts +439 -0
- package/src/business/operation.ts +174 -208
- package/src/business/project-model.ts +258 -0
- package/src/business/project-unlock.ts +172 -112
- package/src/business/project.ts +407 -0
- package/src/business/secret.test.ts +513 -0
- package/src/business/secret.ts +194 -131
- package/src/business/settings.test.ts +695 -0
- package/src/business/settings.ts +855 -0
- package/src/business/terminal-session.ts +90 -0
- package/src/business/unit-extra.test.ts +539 -0
- package/src/business/unit-extra.ts +160 -0
- package/src/business/worker.test.ts +391 -0
- package/src/business/worker.ts +250 -114
- package/src/common/codebase.ts +65 -0
- package/src/common/index.ts +3 -2
- package/src/common/logger.ts +5 -0
- package/src/common/utils.ts +4 -3
- package/src/config.ts +15 -12
- package/src/database/_generated/backend/postgresql/client.ts +72 -0
- package/src/database/_generated/backend/postgresql/commonInputTypes.ts +350 -0
- package/src/database/_generated/backend/postgresql/enums.ts +13 -0
- package/src/database/_generated/backend/postgresql/internal/class.ts +320 -0
- package/src/database/_generated/backend/postgresql/internal/prismaNamespace.ts +1238 -0
- package/src/database/_generated/backend/postgresql/models/Library.ts +1263 -0
- package/src/database/_generated/backend/postgresql/models/Project.ts +2175 -0
- package/src/database/_generated/backend/postgresql/models/ProjectModelStorage.ts +1263 -0
- package/src/database/_generated/backend/postgresql/models/ProjectSpace.ts +1602 -0
- package/src/database/_generated/backend/postgresql/models/PulumiBackend.ts +1263 -0
- package/src/database/_generated/backend/postgresql/models/UserWorkspaseLayout.ts +1065 -0
- package/src/database/_generated/backend/postgresql/models.ts +16 -0
- package/src/database/_generated/backend/postgresql/pjtg.ts +182 -0
- package/src/database/_generated/backend/sqlite/client.ts +72 -0
- package/src/database/_generated/backend/sqlite/commonInputTypes.ts +331 -0
- package/src/database/_generated/backend/sqlite/enums.ts +13 -0
- package/src/database/_generated/backend/sqlite/internal/class.ts +318 -0
- package/src/database/_generated/backend/sqlite/internal/prismaNamespace.ts +1207 -0
- package/src/database/_generated/backend/sqlite/models/Library.ts +1261 -0
- package/src/database/_generated/backend/sqlite/models/Project.ts +2169 -0
- package/src/database/_generated/backend/sqlite/models/ProjectModelStorage.ts +1261 -0
- package/src/database/_generated/backend/sqlite/models/ProjectSpace.ts +1599 -0
- package/src/database/_generated/backend/sqlite/models/PulumiBackend.ts +1261 -0
- package/src/database/_generated/backend/sqlite/models/UserWorkspaseLayout.ts +1063 -0
- package/src/database/_generated/backend/sqlite/models.ts +16 -0
- package/src/database/_generated/backend/sqlite/pjtg.ts +182 -0
- package/src/database/_generated/project/client.ts +204 -0
- package/src/database/_generated/project/commonInputTypes.ts +827 -0
- package/src/database/_generated/project/enums.ts +104 -0
- package/src/database/_generated/project/internal/class.ts +479 -0
- package/src/database/_generated/project/internal/prismaNamespace.ts +2974 -0
- package/src/database/_generated/project/models/ApiKey.ts +1506 -0
- package/src/database/_generated/project/models/Artifact.ts +2051 -0
- package/src/database/_generated/project/models/HubModel.ts +1125 -0
- package/src/database/_generated/project/models/InstanceCustomStatus.ts +1713 -0
- package/src/database/_generated/project/models/InstanceEvaluationState.ts +1312 -0
- package/src/database/_generated/project/models/InstanceLock.ts +1268 -0
- package/src/database/_generated/project/models/InstanceModel.ts +1125 -0
- package/src/database/_generated/project/models/InstanceOperationState.ts +1707 -0
- package/src/database/_generated/project/models/InstanceState.ts +4613 -0
- package/src/database/_generated/project/models/Operation.ts +1647 -0
- package/src/database/_generated/project/models/OperationLog.ts +1455 -0
- package/src/database/_generated/project/models/Page.ts +1838 -0
- package/src/database/_generated/project/models/Secret.ts +1692 -0
- package/src/database/_generated/project/models/ServiceAccount.ts +2165 -0
- package/src/database/_generated/project/models/Terminal.ts +2038 -0
- package/src/database/_generated/project/models/TerminalSession.ts +1454 -0
- package/src/database/_generated/project/models/TerminalSessionLog.ts +1280 -0
- package/src/database/_generated/project/models/Trigger.ts +1430 -0
- package/src/database/_generated/project/models/UnlockMethod.ts +1220 -0
- package/src/database/_generated/project/models/UserCompositeViewport.ts +1280 -0
- package/src/database/_generated/project/models/UserProjectViewport.ts +1059 -0
- package/src/database/_generated/project/models/Worker.ts +1459 -0
- package/src/database/_generated/project/models/WorkerUnitRegistration.ts +1524 -0
- package/src/database/_generated/project/models/WorkerVersion.ts +1974 -0
- package/src/database/_generated/project/models/WorkerVersionLog.ts +1318 -0
- package/src/database/_generated/project/models.ts +35 -0
- package/src/database/_generated/project/pjtg.ts +182 -0
- package/src/database/abstractions.ts +19 -0
- package/src/database/factory.ts +37 -0
- package/src/database/index.ts +6 -0
- package/src/database/local/backend.ts +134 -0
- package/src/database/local/index.ts +3 -0
- package/src/database/local/meta.ts +46 -0
- package/src/database/local/prisma.config.ts +25 -0
- package/src/database/local/project.ts +39 -0
- package/src/database/manager.ts +181 -0
- package/src/database/migrate.ts +35 -0
- package/src/database/prisma.ts +56 -0
- package/src/database/well-known.ts +38 -0
- package/src/index.ts +4 -4
- package/src/library/abstractions.ts +21 -14
- package/src/library/factory.ts +1 -1
- package/src/library/local.ts +86 -38
- package/src/library/package-resolution-worker.ts +1 -1
- package/src/library/worker/evaluator.ts +61 -48
- package/src/library/worker/loader.lite.ts +14 -1
- package/src/library/worker/main.ts +9 -16
- package/src/library/worker/protocol.ts +0 -12
- package/src/lock/manager.ts +12 -7
- package/src/orchestrator/manager.ts +198 -131
- package/src/orchestrator/operation-context.ts +357 -0
- package/src/orchestrator/operation-plan.destroy.test.md +357 -0
- package/src/orchestrator/operation-plan.destroy.test.ts +775 -0
- package/src/orchestrator/operation-plan.fixtures.ts +213 -0
- package/src/orchestrator/operation-plan.md +198 -0
- package/src/orchestrator/operation-plan.refresh.test.md +199 -0
- package/src/orchestrator/operation-plan.refresh.test.ts +367 -0
- package/src/orchestrator/operation-plan.ts +709 -0
- package/src/orchestrator/operation-plan.update.test.md +485 -0
- package/src/orchestrator/operation-plan.update.test.ts +1066 -0
- package/src/orchestrator/operation-workset.ts +235 -583
- package/src/orchestrator/operation.ts +446 -904
- package/src/orchestrator/plan-test-builder.ts +267 -0
- package/src/project-model/abstractions.ts +118 -0
- package/src/project-model/backends/codebase.ts +365 -0
- package/src/project-model/backends/database.ts +440 -0
- package/src/project-model/errors.ts +81 -0
- package/src/project-model/factory.ts +24 -0
- package/src/project-model/index.ts +4 -0
- package/src/project-model/utils.test.ts +544 -0
- package/src/project-model/utils.ts +242 -0
- package/src/pubsub/abstractions.ts +10 -1
- package/src/pubsub/factory.ts +4 -4
- package/src/pubsub/index.ts +1 -0
- package/src/pubsub/manager.ts +49 -25
- package/src/pubsub/memory.ts +31 -0
- package/src/runner/abstractions.ts +38 -26
- package/src/runner/artifact-env.ts +17 -6
- package/src/runner/factory.ts +6 -6
- package/src/runner/force-abort.ts +3 -6
- package/src/runner/local.ts +79 -72
- package/src/runner/pulumi.ts +26 -63
- package/src/services.ts +214 -103
- package/src/shared/models/backend/index.ts +3 -1
- package/src/shared/models/backend/library.ts +12 -4
- package/src/shared/models/backend/project.ts +43 -23
- package/src/shared/models/backend/pulumi.ts +14 -0
- package/src/shared/models/backend/unlock-method.ts +1 -1
- package/src/shared/models/backend/well-known.ts +58 -0
- package/src/shared/models/base.ts +40 -109
- package/src/shared/models/errors.ts +82 -1
- package/src/shared/models/index.ts +3 -2
- package/src/shared/models/prisma.ts +36 -0
- package/src/shared/models/project/api-key.ts +37 -56
- package/src/shared/models/project/artifact.ts +15 -105
- package/src/shared/models/project/custom-status.ts +12 -0
- package/src/shared/models/project/index.ts +9 -9
- package/src/shared/models/project/lock.ts +10 -78
- package/src/shared/models/project/model.ts +32 -0
- package/src/shared/models/project/operation.ts +222 -99
- package/src/shared/models/project/page.ts +37 -48
- package/src/shared/models/project/secret.ts +29 -103
- package/src/shared/models/project/service-account.ts +12 -17
- package/src/shared/models/project/state.ts +100 -390
- package/src/shared/models/project/terminal.ts +75 -89
- package/src/shared/models/project/trigger.ts +13 -49
- package/src/shared/models/project/unlock-method.ts +21 -20
- package/src/shared/models/project/worker.ts +89 -88
- package/src/shared/resolvers/graph-resolver.ts +62 -26
- package/src/shared/resolvers/index.ts +1 -1
- package/src/shared/resolvers/input-hash.ts +24 -14
- package/src/shared/resolvers/input.ts +48 -6
- package/src/shared/resolvers/registry.ts +5 -4
- package/src/shared/resolvers/state.ts +12 -1
- package/src/shared/resolvers/validation.ts +29 -9
- package/src/shared/utils/index.ts +1 -1
- package/src/shared/utils/promise-tracker.ts +30 -3
- package/src/terminal/abstractions.ts +1 -1
- package/src/terminal/docker.ts +3 -3
- package/src/terminal/manager.ts +102 -118
- package/src/test-utils/database.ts +119 -0
- package/src/test-utils/index.ts +2 -0
- package/src/test-utils/services.ts +134 -0
- package/src/unlock/abstractions.ts +31 -0
- package/src/unlock/index.ts +2 -0
- package/src/unlock/memory.ts +27 -0
- package/src/worker/abstractions.ts +7 -4
- package/src/worker/docker.ts +14 -19
- package/src/worker/manager.ts +376 -79
- package/dist/chunk-RCB4AFGD.js.map +0 -1
- package/dist/chunk-WHALQHEZ.js +0 -2017
- package/dist/chunk-WHALQHEZ.js.map +0 -1
- package/src/business/backend-unlock.ts +0 -10
- package/src/common/performance.ts +0 -44
- package/src/hotstate/abstractions.ts +0 -48
- package/src/hotstate/factory.ts +0 -17
- package/src/hotstate/index.ts +0 -3
- package/src/hotstate/manager.ts +0 -192
- package/src/hotstate/memory.ts +0 -100
- package/src/hotstate/validation.ts +0 -101
- package/src/project/abstractions.ts +0 -102
- package/src/project/factory.ts +0 -11
- package/src/project/index.ts +0 -3
- package/src/project/local.ts +0 -469
- package/src/project/manager.ts +0 -574
- package/src/pubsub/local.ts +0 -36
- package/src/pubsub/validation.ts +0 -33
- package/src/shared/models/project/component.ts +0 -45
- package/src/shared/models/project/instance.ts +0 -74
- package/src/state/abstractions.ts +0 -450
- package/src/state/encryption.ts +0 -59
- package/src/state/factory.ts +0 -20
- package/src/state/index.ts +0 -6
- package/src/state/local/backend.ts +0 -299
- package/src/state/local/collection.ts +0 -342
- package/src/state/local/index.ts +0 -2
- package/src/state/manager.ts +0 -819
- package/src/state/repository/index.ts +0 -2
- package/src/state/repository/repository.index.ts +0 -193
- package/src/state/repository/repository.ts +0 -458
- /package/src/{state → database/local}/keyring.ts +0 -0
package/src/business/worker.ts
CHANGED
|
@@ -1,161 +1,297 @@
|
|
|
1
|
+
import type { CommonObjectMeta, UnitWorker } from "@highstate/contract"
|
|
1
2
|
import type { Logger } from "pino"
|
|
2
|
-
import type {
|
|
3
|
+
import type {
|
|
4
|
+
DatabaseManager,
|
|
5
|
+
ProjectTransaction,
|
|
6
|
+
Worker,
|
|
7
|
+
WorkerVersion,
|
|
8
|
+
WorkerVersionLog,
|
|
9
|
+
} from "../database"
|
|
10
|
+
import type { PubSubManager } from "../pubsub"
|
|
3
11
|
import type { WorkerManager } from "../worker"
|
|
4
|
-
import type { InstanceStateService } from "./instance-state"
|
|
5
12
|
import { randomBytes } from "node:crypto"
|
|
6
|
-
import {
|
|
13
|
+
import { PrismaClientKnownRequestError } from "@prisma/client/runtime/client"
|
|
14
|
+
import { createProjectLogger } from "../common"
|
|
7
15
|
import {
|
|
16
|
+
extractDigestFromImage,
|
|
8
17
|
getWorkerIdentity,
|
|
9
|
-
type
|
|
10
|
-
type ProjectApiKey,
|
|
11
|
-
type ServiceAccount,
|
|
12
|
-
type UnitWorker,
|
|
13
|
-
type Worker,
|
|
14
|
-
type WorkerUnitRegistration,
|
|
18
|
+
type WorkerUnitRegistrationEvent,
|
|
15
19
|
} from "../shared"
|
|
16
|
-
import {
|
|
20
|
+
import { WorkerVersionNotFoundError } from "../shared/models/errors"
|
|
17
21
|
|
|
18
22
|
export class WorkerService {
|
|
19
23
|
constructor(
|
|
20
|
-
private readonly
|
|
24
|
+
private readonly database: DatabaseManager,
|
|
21
25
|
private readonly workerManager: WorkerManager,
|
|
22
|
-
private readonly
|
|
23
|
-
private readonly instanceStateService: InstanceStateService,
|
|
26
|
+
private readonly pubsubManager: PubSubManager,
|
|
24
27
|
private readonly logger: Logger,
|
|
25
28
|
) {}
|
|
26
29
|
|
|
27
|
-
|
|
30
|
+
/**
|
|
31
|
+
* Updates unit worker registrations for an instance in a single transaction
|
|
32
|
+
* creates workers and worker versions as needed and cleans up removed registrations
|
|
33
|
+
*
|
|
34
|
+
* @param tx The transaction to use for database operations.
|
|
35
|
+
* @param projectId The ID of the project containing the instance.
|
|
36
|
+
* @param stateId The ID of the instance state to update registrations for.
|
|
37
|
+
* @param unitWorkers The list workers provided by the unit.
|
|
38
|
+
*/
|
|
39
|
+
async updateUnitRegistrations(
|
|
40
|
+
tx: ProjectTransaction,
|
|
28
41
|
projectId: string,
|
|
29
|
-
|
|
30
|
-
|
|
42
|
+
stateId: string,
|
|
43
|
+
unitWorkers: UnitWorker[],
|
|
31
44
|
): Promise<void> {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
const existingReg = existingRegistrations.find(reg => reg.image === unitWorker.image)
|
|
38
|
-
if (existingReg && JSON.stringify(existingReg.params) === JSON.stringify(unitWorker.params)) {
|
|
39
|
-
this.logger.debug(
|
|
40
|
-
`instance "%s" already registered with worker "%s" with the same parameters`,
|
|
41
|
-
state.id,
|
|
42
|
-
unitWorker.image,
|
|
43
|
-
)
|
|
44
|
-
return
|
|
45
|
-
}
|
|
45
|
+
// parse images first
|
|
46
|
+
const parsedWorkers = unitWorkers.map(w => {
|
|
47
|
+
const digest = extractDigestFromImage(w.image)
|
|
48
|
+
const identity = getWorkerIdentity(w.image)
|
|
46
49
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
workerId = await this.ensureWorkerCreated(projectId, unitWorker)
|
|
50
|
-
}
|
|
50
|
+
return { ...w, digest, identity }
|
|
51
|
+
})
|
|
51
52
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
}
|
|
53
|
+
const logger = createProjectLogger(this.logger, projectId)
|
|
54
|
+
|
|
55
|
+
const eventsToPublish: { workerVersionId: string; event: WorkerUnitRegistrationEvent }[] = []
|
|
56
|
+
|
|
57
|
+
// query all registrations for the instance
|
|
58
|
+
const existingRegistrations = await tx.workerUnitRegistration.findMany({
|
|
59
|
+
where: { stateId },
|
|
60
|
+
select: { stateId: true, name: true, params: true, workerVersionId: true },
|
|
61
|
+
})
|
|
60
62
|
|
|
61
|
-
|
|
63
|
+
// the set of names we want to keep
|
|
64
|
+
const desiredNames = new Set(parsedWorkers.map(w => w.name))
|
|
62
65
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
+
for (const worker of parsedWorkers) {
|
|
67
|
+
const workerRecord = await this.ensureWorker(tx, worker.identity)
|
|
68
|
+
const workerVersionRecord = await this.ensureWorkerVersion(tx, workerRecord, worker.digest)
|
|
66
69
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
await this.stateManager
|
|
70
|
-
.getWorkerRegistrationIndexRepository(projectId, workerId)
|
|
71
|
-
.indexRepository.put(registration.id, SAME_KEY, batch)
|
|
70
|
+
const existing = existingRegistrations.find(r => r.name === worker.name)
|
|
71
|
+
const stringifiedParams = JSON.stringify(worker.params)
|
|
72
72
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
73
|
+
// create a new registration if it doesn't exist
|
|
74
|
+
if (!existing) {
|
|
75
|
+
await tx.workerUnitRegistration.create({
|
|
76
|
+
data: {
|
|
77
|
+
stateId,
|
|
78
|
+
name: worker.name,
|
|
79
|
+
params: worker.params,
|
|
80
|
+
workerVersionId: workerVersionRecord.id,
|
|
78
81
|
},
|
|
79
82
|
})
|
|
83
|
+
|
|
84
|
+
eventsToPublish.push({
|
|
85
|
+
workerVersionId: workerVersionRecord.id,
|
|
86
|
+
event: { type: "registered", instanceId: stateId, params: worker.params },
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
continue
|
|
80
90
|
}
|
|
81
91
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
}
|
|
92
|
+
const paramsChanged = JSON.stringify(existing.params) !== stringifiedParams
|
|
93
|
+
const versionChanged = existing.workerVersionId !== workerVersionRecord.id
|
|
85
94
|
|
|
86
|
-
|
|
87
|
-
|
|
95
|
+
// update existing registration if params or version changed
|
|
96
|
+
if (paramsChanged || versionChanged) {
|
|
97
|
+
await tx.workerUnitRegistration.update({
|
|
98
|
+
where: { stateId_name: { stateId, name: worker.name } },
|
|
99
|
+
data: {
|
|
100
|
+
params: worker.params,
|
|
101
|
+
workerVersionId: workerVersionRecord.id,
|
|
102
|
+
},
|
|
103
|
+
})
|
|
88
104
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
105
|
+
// deregister from old worker version if it changed
|
|
106
|
+
if (versionChanged) {
|
|
107
|
+
eventsToPublish.push({
|
|
108
|
+
workerVersionId: existing.workerVersionId,
|
|
109
|
+
event: { type: "deregistered", instanceId: stateId },
|
|
110
|
+
})
|
|
111
|
+
}
|
|
92
112
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
113
|
+
eventsToPublish.push({
|
|
114
|
+
workerVersionId: workerVersionRecord.id,
|
|
115
|
+
event: { type: "registered", instanceId: stateId, params: worker.params },
|
|
116
|
+
})
|
|
97
117
|
}
|
|
118
|
+
}
|
|
98
119
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
identity,
|
|
106
|
-
)
|
|
120
|
+
// remove registrations that are no longer desired
|
|
121
|
+
for (const registration of existingRegistrations) {
|
|
122
|
+
if (!desiredNames.has(registration.name)) {
|
|
123
|
+
await tx.workerUnitRegistration.delete({
|
|
124
|
+
where: { stateId_name: { stateId, name: registration.name } },
|
|
125
|
+
})
|
|
107
126
|
|
|
108
|
-
|
|
127
|
+
eventsToPublish.push({
|
|
128
|
+
workerVersionId: registration.workerVersionId,
|
|
129
|
+
event: { type: "deregistered", instanceId: stateId },
|
|
130
|
+
})
|
|
109
131
|
}
|
|
132
|
+
}
|
|
110
133
|
|
|
111
|
-
|
|
134
|
+
await this.cleanupUnusedWorkerVersions(tx)
|
|
112
135
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
136
|
+
// publish events after transaction commits
|
|
137
|
+
for (const { workerVersionId, event } of eventsToPublish) {
|
|
138
|
+
void this.pubsubManager.publish(
|
|
139
|
+
["worker-unit-registration", projectId, workerVersionId],
|
|
140
|
+
event,
|
|
141
|
+
)
|
|
142
|
+
}
|
|
120
143
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
.getServiceAccountRepository(projectId)
|
|
124
|
-
.putItem(serviceAccount, batch)
|
|
125
|
-
}
|
|
144
|
+
// ensure all worker versions are started
|
|
145
|
+
void this.workerManager.syncWorkers(projectId)
|
|
126
146
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
serviceAccountIds: [serviceAccountId],
|
|
136
|
-
},
|
|
137
|
-
],
|
|
138
|
-
}
|
|
147
|
+
logger.info(`updated worker registrations for instance state "%s"`, stateId)
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
private async ensureWorker(tx: ProjectTransaction, identity: string): Promise<Worker> {
|
|
151
|
+
const existing = await tx.worker.findUnique({ where: { identity } })
|
|
152
|
+
if (existing) {
|
|
153
|
+
return existing
|
|
154
|
+
}
|
|
139
155
|
|
|
140
|
-
|
|
156
|
+
// create a new service account for the worker
|
|
157
|
+
const serviceAccount = await tx.serviceAccount.create({
|
|
158
|
+
select: { id: true },
|
|
159
|
+
data: {
|
|
160
|
+
meta: {
|
|
161
|
+
// this generic meta should be replaced by the worker when it starts
|
|
162
|
+
title: "Worker Service Account",
|
|
163
|
+
description: `Automatically created for worker "${identity}".`,
|
|
164
|
+
},
|
|
165
|
+
},
|
|
166
|
+
})
|
|
141
167
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
meta: {},
|
|
145
|
-
status: "starting",
|
|
146
|
-
failedStartAttempts: 5,
|
|
168
|
+
return await tx.worker.create({
|
|
169
|
+
data: {
|
|
147
170
|
identity,
|
|
148
|
-
|
|
149
|
-
|
|
171
|
+
serviceAccountId: serviceAccount.id,
|
|
172
|
+
},
|
|
173
|
+
})
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
private async ensureWorkerVersion(
|
|
177
|
+
tx: ProjectTransaction,
|
|
178
|
+
worker: Worker,
|
|
179
|
+
digest: string,
|
|
180
|
+
): Promise<WorkerVersion> {
|
|
181
|
+
const existing = await tx.workerVersion.findUnique({ where: { digest } })
|
|
182
|
+
if (existing) {
|
|
183
|
+
return existing
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// create an API key for the worker granting full access to its service account
|
|
187
|
+
const apiKey = await tx.apiKey.create({
|
|
188
|
+
data: {
|
|
189
|
+
meta: {
|
|
190
|
+
title: `Worker API Key for "${worker.identity}"`,
|
|
191
|
+
description: `Automatically created for worker "${worker.identity}" with digest "${digest}".`,
|
|
192
|
+
},
|
|
193
|
+
serviceAccountId: worker.serviceAccountId,
|
|
194
|
+
token: randomBytes(32).toString("hex"),
|
|
195
|
+
},
|
|
196
|
+
})
|
|
197
|
+
|
|
198
|
+
return await tx.workerVersion.create({
|
|
199
|
+
data: {
|
|
200
|
+
workerId: worker.id,
|
|
201
|
+
digest,
|
|
202
|
+
meta: {
|
|
203
|
+
title: "Worker Version",
|
|
204
|
+
description: `Worker version with digest ${digest}`,
|
|
205
|
+
},
|
|
150
206
|
apiKeyId: apiKey.id,
|
|
207
|
+
},
|
|
208
|
+
})
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Performs cleanup of unused worker versions and syncs workers for a project.
|
|
213
|
+
* This method should be called after operations that may leave unused workers.
|
|
214
|
+
*
|
|
215
|
+
* @param projectId The ID of the project to cleanup and sync workers for.
|
|
216
|
+
*/
|
|
217
|
+
async cleanupWorkerUsageAndSync(projectId: string): Promise<void> {
|
|
218
|
+
const database = await this.database.forProject(projectId)
|
|
219
|
+
|
|
220
|
+
await database.$transaction(async tx => {
|
|
221
|
+
await this.cleanupUnusedWorkerVersions(tx)
|
|
222
|
+
})
|
|
223
|
+
|
|
224
|
+
// ensure all worker versions are started
|
|
225
|
+
void this.workerManager.syncWorkers(projectId)
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
private async cleanupUnusedWorkerVersions(tx: ProjectTransaction): Promise<void> {
|
|
229
|
+
const unused = await tx.workerVersion.findMany({
|
|
230
|
+
where: {
|
|
231
|
+
unitRegistrations: { none: {} },
|
|
232
|
+
},
|
|
233
|
+
select: { id: true },
|
|
234
|
+
})
|
|
235
|
+
|
|
236
|
+
if (unused.length === 0) {
|
|
237
|
+
return
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
await tx.workerVersion.deleteMany({
|
|
241
|
+
where: { id: { in: unused.map(u => u.id) } },
|
|
242
|
+
})
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Updates the metadata for a worker version.
|
|
247
|
+
*
|
|
248
|
+
* @param projectId The ID of the project.
|
|
249
|
+
* @param workerVersionId The ID of the worker version to update.
|
|
250
|
+
* @param meta The new metadata to set.
|
|
251
|
+
*/
|
|
252
|
+
async updateWorkerVersionMeta(
|
|
253
|
+
projectId: string,
|
|
254
|
+
workerVersionId: string,
|
|
255
|
+
meta: CommonObjectMeta,
|
|
256
|
+
): Promise<void> {
|
|
257
|
+
const database = await this.database.forProject(projectId)
|
|
258
|
+
const logger = createProjectLogger(this.logger, projectId)
|
|
259
|
+
|
|
260
|
+
try {
|
|
261
|
+
await database.workerVersion.update({
|
|
262
|
+
where: { id: workerVersionId },
|
|
263
|
+
data: { meta },
|
|
264
|
+
})
|
|
265
|
+
} catch (error) {
|
|
266
|
+
if (error instanceof PrismaClientKnownRequestError && error.code === "P2025") {
|
|
267
|
+
throw new WorkerVersionNotFoundError(projectId, workerVersionId)
|
|
151
268
|
}
|
|
152
269
|
|
|
153
|
-
|
|
154
|
-
|
|
270
|
+
throw error
|
|
271
|
+
}
|
|
155
272
|
|
|
156
|
-
|
|
273
|
+
logger.info(`updated worker version metadata for "%s"`, workerVersionId)
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Gets logs for a worker version.
|
|
278
|
+
*
|
|
279
|
+
* @param projectId The ID of the project.
|
|
280
|
+
* @param workerVersionId The ID of the worker version to get logs for.
|
|
281
|
+
*/
|
|
282
|
+
async getWorkerVersionLogs(
|
|
283
|
+
projectId: string,
|
|
284
|
+
workerVersionId: string,
|
|
285
|
+
): Promise<WorkerVersionLog[]> {
|
|
286
|
+
const database = await this.database.forProject(projectId)
|
|
157
287
|
|
|
158
|
-
|
|
288
|
+
return await database.workerVersionLog.findMany({
|
|
289
|
+
where: {
|
|
290
|
+
workerVersionId,
|
|
291
|
+
},
|
|
292
|
+
orderBy: {
|
|
293
|
+
id: "asc",
|
|
294
|
+
},
|
|
159
295
|
})
|
|
160
296
|
}
|
|
161
297
|
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { Logger } from "pino"
|
|
2
|
+
import { mkdir } from "node:fs/promises"
|
|
3
|
+
import { dirname, relative } from "node:path"
|
|
4
|
+
import { resolvePackageJSON } from "pkg-types"
|
|
5
|
+
import z from "zod"
|
|
6
|
+
|
|
7
|
+
export const codebaseConfig = z.object({
|
|
8
|
+
HIGHSTATE_CODEBASE_PATH: z.string().optional(),
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
let codebasePath: Promise<string> | undefined
|
|
12
|
+
let codebaseHighstatePath: Promise<string> | undefined
|
|
13
|
+
|
|
14
|
+
async function _getCodebasePath(
|
|
15
|
+
config: z.infer<typeof codebaseConfig>,
|
|
16
|
+
logger: Logger,
|
|
17
|
+
): Promise<string> {
|
|
18
|
+
if (config.HIGHSTATE_CODEBASE_PATH) {
|
|
19
|
+
return config.HIGHSTATE_CODEBASE_PATH
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const packageJson = await resolvePackageJSON()
|
|
23
|
+
const path = dirname(packageJson)
|
|
24
|
+
|
|
25
|
+
if (path !== process.cwd()) {
|
|
26
|
+
const relativePath = relative(process.cwd(), path)
|
|
27
|
+
logger.info(`detected "%s" as codebase path`, relativePath)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return path
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export async function getCodebasePath(
|
|
34
|
+
config: z.infer<typeof codebaseConfig>,
|
|
35
|
+
logger: Logger,
|
|
36
|
+
): Promise<string> {
|
|
37
|
+
if (!codebasePath) {
|
|
38
|
+
codebasePath = _getCodebasePath(config, logger)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return codebasePath
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async function _getCodebaseHighstatePath(
|
|
45
|
+
config: z.infer<typeof codebaseConfig>,
|
|
46
|
+
logger: Logger,
|
|
47
|
+
): Promise<string> {
|
|
48
|
+
const path = await getCodebasePath(config, logger)
|
|
49
|
+
|
|
50
|
+
const highstatePath = `${path}/.highstate`
|
|
51
|
+
await mkdir(highstatePath, { recursive: true })
|
|
52
|
+
|
|
53
|
+
return highstatePath
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export async function getCodebaseHighstatePath(
|
|
57
|
+
config: z.infer<typeof codebaseConfig>,
|
|
58
|
+
logger: Logger,
|
|
59
|
+
): Promise<string> {
|
|
60
|
+
if (!codebaseHighstatePath) {
|
|
61
|
+
codebaseHighstatePath = _getCodebaseHighstatePath(config, logger)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return codebaseHighstatePath
|
|
65
|
+
}
|
package/src/common/index.ts
CHANGED
package/src/common/utils.ts
CHANGED
|
@@ -25,8 +25,9 @@ export async function runWithRetryOnError<T>(
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
export class AbortError extends Error {
|
|
28
|
-
constructor(options?: ErrorOptions) {
|
|
29
|
-
super(
|
|
28
|
+
constructor(message: string, options?: ErrorOptions) {
|
|
29
|
+
super(message, options)
|
|
30
|
+
this.name = "AbortError"
|
|
30
31
|
}
|
|
31
32
|
}
|
|
32
33
|
|
|
@@ -58,7 +59,7 @@ export function isAbortErrorLike(error: unknown): boolean {
|
|
|
58
59
|
|
|
59
60
|
export function tryWrapAbortErrorLike(error: unknown): unknown {
|
|
60
61
|
if (isAbortErrorLike(error)) {
|
|
61
|
-
return new AbortError({ cause: error })
|
|
62
|
+
return new AbortError("Operation aborted", { cause: error })
|
|
62
63
|
}
|
|
63
64
|
|
|
64
65
|
return error
|
package/src/config.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { z } from "zod"
|
|
2
|
-
import { libraryBackendConfig } from "./library"
|
|
3
|
-
import { projectBackendConfig } from "./project"
|
|
4
|
-
import { terminalBackendConfig } from "./terminal"
|
|
5
|
-
import { runnerBackendConfig } from "./runner"
|
|
6
|
-
import { stateBackendConfig, stateManagerConfig } from "./state"
|
|
7
2
|
import { artifactBackendConfig } from "./artifact"
|
|
8
|
-
import {
|
|
3
|
+
import { projectUnlockServiceConfig } from "./business"
|
|
4
|
+
import { codebaseConfig } from "./common"
|
|
5
|
+
import { databaseConfig } from "./database"
|
|
6
|
+
import { libraryBackendConfig } from "./library"
|
|
9
7
|
import { lockBackendConfig } from "./lock"
|
|
10
|
-
import {
|
|
8
|
+
import { pubSubBackendConfig } from "./pubsub"
|
|
9
|
+
import { runnerBackendConfig } from "./runner"
|
|
10
|
+
import { terminalBackendConfig } from "./terminal"
|
|
11
11
|
import { workerBackendConfig, workerManagerConfig } from "./worker"
|
|
12
12
|
|
|
13
13
|
const loggerConfig = z.object({
|
|
@@ -15,13 +15,12 @@ const loggerConfig = z.object({
|
|
|
15
15
|
})
|
|
16
16
|
|
|
17
17
|
const configSchema = z.object({
|
|
18
|
-
...
|
|
18
|
+
...codebaseConfig.shape,
|
|
19
|
+
...databaseConfig.shape,
|
|
19
20
|
...pubSubBackendConfig.shape,
|
|
20
21
|
...lockBackendConfig.shape,
|
|
21
22
|
...libraryBackendConfig.shape,
|
|
22
|
-
...
|
|
23
|
-
...stateBackendConfig.shape,
|
|
24
|
-
...stateManagerConfig.shape,
|
|
23
|
+
...projectUnlockServiceConfig.shape,
|
|
25
24
|
...runnerBackendConfig.shape,
|
|
26
25
|
...terminalBackendConfig.shape,
|
|
27
26
|
...workerBackendConfig.shape,
|
|
@@ -40,5 +39,9 @@ export async function loadConfig(
|
|
|
40
39
|
await import("dotenv/config")
|
|
41
40
|
}
|
|
42
41
|
|
|
43
|
-
|
|
42
|
+
try {
|
|
43
|
+
return configSchema.parse(env)
|
|
44
|
+
} catch (error) {
|
|
45
|
+
throw new Error("Failed to parse backend configuration", { cause: error })
|
|
46
|
+
}
|
|
44
47
|
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
|
|
2
|
+
/* !!! This is code generated by Prisma. Do not edit directly. !!! */
|
|
3
|
+
/* eslint-disable */
|
|
4
|
+
// @ts-nocheck
|
|
5
|
+
/**
|
|
6
|
+
* This file should be your main import to use Prisma. Through it you get access to all the models, enums, and input types.
|
|
7
|
+
*
|
|
8
|
+
* 🟢 You can import this file directly.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import * as process from 'node:process'
|
|
12
|
+
import * as path from 'node:path'
|
|
13
|
+
import { fileURLToPath } from 'node:url'
|
|
14
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
15
|
+
|
|
16
|
+
import * as runtime from "@prisma/client/runtime/client"
|
|
17
|
+
import * as $Enums from "./enums.ts"
|
|
18
|
+
import * as $Class from "./internal/class.ts"
|
|
19
|
+
import * as Prisma from "./internal/prismaNamespace.ts"
|
|
20
|
+
|
|
21
|
+
export * as $Enums from './enums.ts'
|
|
22
|
+
/**
|
|
23
|
+
* ## Prisma Client
|
|
24
|
+
*
|
|
25
|
+
* Type-safe database client for TypeScript
|
|
26
|
+
* @example
|
|
27
|
+
* ```
|
|
28
|
+
* const prisma = new PrismaClient()
|
|
29
|
+
* // Fetch zero or more UserWorkspaseLayouts
|
|
30
|
+
* const userWorkspaseLayouts = await prisma.userWorkspaseLayout.findMany()
|
|
31
|
+
* ```
|
|
32
|
+
*
|
|
33
|
+
* Read more in our [docs](https://www.prisma.io/docs/reference/tools-and-interfaces/prisma-client).
|
|
34
|
+
*/
|
|
35
|
+
export const PrismaClient = $Class.getPrismaClientClass(__dirname)
|
|
36
|
+
export type PrismaClient<LogOpts extends Prisma.LogLevel = never, OmitOpts extends Prisma.PrismaClientOptions["omit"] = Prisma.PrismaClientOptions["omit"], ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = $Class.PrismaClient<LogOpts, OmitOpts, ExtArgs>
|
|
37
|
+
export { Prisma }
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Model UserWorkspaseLayout
|
|
43
|
+
*
|
|
44
|
+
*/
|
|
45
|
+
export type UserWorkspaseLayout = Prisma.UserWorkspaseLayoutModel
|
|
46
|
+
/**
|
|
47
|
+
* Model Library
|
|
48
|
+
*
|
|
49
|
+
*/
|
|
50
|
+
export type Library = Prisma.LibraryModel
|
|
51
|
+
/**
|
|
52
|
+
* Model Project
|
|
53
|
+
*
|
|
54
|
+
*/
|
|
55
|
+
export type Project = Prisma.ProjectModel
|
|
56
|
+
/**
|
|
57
|
+
* Model ProjectSpace
|
|
58
|
+
*
|
|
59
|
+
*/
|
|
60
|
+
export type ProjectSpace = Prisma.ProjectSpaceModel
|
|
61
|
+
/**
|
|
62
|
+
* Model ProjectModelStorage
|
|
63
|
+
*
|
|
64
|
+
*/
|
|
65
|
+
export type ProjectModelStorage = Prisma.ProjectModelStorageModel
|
|
66
|
+
/**
|
|
67
|
+
* Model PulumiBackend
|
|
68
|
+
*
|
|
69
|
+
*/
|
|
70
|
+
export type PulumiBackend = Prisma.PulumiBackendModel
|
|
71
|
+
|
|
72
|
+
|