@highstate/backend 0.9.18 → 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-OU5OQBLB.js → chunk-I7BWSAN6.js} +3 -28
- package/dist/{chunk-OU5OQBLB.js.map → chunk-I7BWSAN6.js.map} +1 -1
- package/dist/chunk-VB4YL327.js +139 -0
- 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 +2 -1
- package/dist/index.js +7587 -7291
- package/dist/index.js.map +1 -1
- package/dist/library/package-resolution-worker.js +1 -1
- package/dist/library/package-resolution-worker.js.map +1 -1
- package/dist/library/worker/main.js +35 -29
- package/dist/library/worker/main.js.map +1 -1
- package/dist/shared/index.js +2 -2
- package/package.json +18 -9
- 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 +30 -54
- package/src/artifact/factory.ts +6 -9
- package/src/artifact/local.ts +33 -46
- package/src/business/api-key.ts +24 -36
- package/src/business/artifact.test.ts +978 -0
- package/src/business/artifact.ts +136 -216
- package/src/business/evaluation.ts +328 -0
- package/src/business/index.ts +5 -2
- package/src/business/instance-lock.test.ts +1060 -0
- package/src/business/instance-lock.ts +387 -78
- package/src/business/instance-state.test.ts +735 -0
- package/src/business/instance-state.ts +582 -337
- 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 +168 -126
- package/src/business/project.ts +287 -179
- package/src/business/secret.test.ts +465 -130
- package/src/business/secret.ts +186 -217
- 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 +356 -579
- package/src/business/worker.ts +238 -339
- package/src/common/codebase.ts +65 -0
- package/src/common/index.ts +3 -5
- package/src/common/logger.ts +5 -0
- package/src/common/utils.ts +4 -3
- package/src/config.ts +10 -11
- 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 +3 -5
- package/src/library/factory.ts +1 -1
- package/src/library/local.ts +81 -26
- package/src/library/package-resolution-worker.ts +1 -1
- package/src/library/worker/evaluator.ts +40 -23
- package/src/library/worker/loader.lite.ts +1 -1
- package/src/library/worker/main.ts +3 -10
- package/src/library/worker/protocol.ts +0 -1
- package/src/lock/index.ts +0 -1
- package/src/lock/manager.ts +0 -10
- package/src/orchestrator/manager.ts +190 -104
- 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 +233 -578
- package/src/orchestrator/operation.ts +435 -948
- 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 +29 -13
- package/src/pubsub/memory.ts +31 -0
- package/src/runner/abstractions.ts +33 -41
- package/src/runner/artifact-env.ts +19 -8
- package/src/runner/factory.ts +6 -6
- package/src/runner/force-abort.ts +3 -6
- package/src/runner/local.ts +64 -67
- package/src/runner/pulumi.ts +23 -63
- package/src/services.ts +181 -123
- package/src/shared/models/backend/index.ts +3 -1
- package/src/shared/models/backend/library.ts +9 -1
- package/src/shared/models/backend/project.ts +43 -42
- 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 -26
- 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 -59
- package/src/shared/models/project/artifact.ts +16 -76
- package/src/shared/models/project/custom-status.ts +12 -0
- package/src/shared/models/project/index.ts +8 -7
- package/src/shared/models/project/lock.ts +10 -78
- package/src/shared/models/project/model.ts +19 -1
- 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 -89
- package/src/shared/models/project/service-account.ts +12 -17
- package/src/shared/models/project/state.ts +100 -407
- package/src/shared/models/project/terminal.ts +75 -88
- package/src/shared/models/project/trigger.ts +13 -49
- package/src/shared/models/project/unlock-method.ts +20 -26
- package/src/shared/models/project/worker.ts +89 -90
- package/src/shared/resolvers/graph-resolver.ts +21 -0
- package/src/shared/resolvers/index.ts +1 -1
- package/src/shared/resolvers/input-hash.ts +24 -14
- package/src/shared/resolvers/input.ts +1 -1
- package/src/shared/resolvers/registry.ts +5 -4
- package/src/shared/resolvers/state.ts +12 -1
- package/src/shared/resolvers/validation.ts +7 -3
- package/src/shared/utils/index.ts +1 -2
- 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 +5 -23
- package/src/unlock/memory.ts +9 -14
- package/src/worker/abstractions.ts +7 -4
- package/src/worker/docker.ts +14 -19
- package/src/worker/manager.ts +366 -97
- package/dist/chunk-NAAIDR4U.js +0 -8499
- package/dist/chunk-NAAIDR4U.js.map +0 -1
- package/dist/chunk-Y7DXREVO.js +0 -1745
- package/dist/chunk-Y7DXREVO.js.map +0 -1
- package/dist/magic-string.es-5ABAC4JN.js +0 -1292
- package/dist/magic-string.es-5ABAC4JN.js.map +0 -1
- package/src/business/__traces__/secret/update-instance-secrets/create-and-delete-secrets-simultaneously.md +0 -356
- package/src/business/__traces__/secret/update-instance-secrets/create-new-secrets-for-instance.md +0 -274
- package/src/business/__traces__/secret/update-instance-secrets/delete-existing-secrets.md +0 -223
- package/src/business/__traces__/secret/update-instance-secrets/no-op-when-no-changes.md +0 -147
- package/src/business/__traces__/secret/update-instance-secrets/update-existing-secrets.md +0 -280
- package/src/business/__traces__/worker/update-unit-registrations/add-new-unit-registration-when-other-exists.md +0 -360
- package/src/business/__traces__/worker/update-unit-registrations/add-new-unit-registration.md +0 -215
- package/src/business/__traces__/worker/update-unit-registrations/create-multiple-workers-with-different-identities.md +0 -427
- package/src/business/__traces__/worker/update-unit-registrations/handle-nonexistent-registration-id-gracefully.md +0 -217
- package/src/business/__traces__/worker/update-unit-registrations/no-op-when-no-changes.md +0 -132
- package/src/business/__traces__/worker/update-unit-registrations/recreate-worker-when-image-changes.md +0 -454
- package/src/business/__traces__/worker/update-unit-registrations/recreate-worker-when-image-version-changes.md +0 -426
- package/src/business/__traces__/worker/update-unit-registrations/recreate-worker-with-same-identity-reuses-service-account.md +0 -372
- package/src/business/__traces__/worker/update-unit-registrations/remove-one-of-multiple-unit-registrations.md +0 -383
- package/src/business/__traces__/worker/update-unit-registrations/remove-unit-registration.md +0 -245
- package/src/business/__traces__/worker/update-unit-registrations/update-existing-unit-registration-when-params-change.md +0 -174
- package/src/business/__traces__/worker/update-unit-registrations/update-params-and-image-simultaneously.md +0 -432
- package/src/business/__traces__/worker/update-unit-registrations/worker-with-multiple-registrations-not-deleted-when-one-removed.md +0 -220
- package/src/business/backend-unlock.ts +0 -10
- package/src/common/clock.ts +0 -18
- package/src/common/performance.ts +0 -44
- package/src/common/random.ts +0 -68
- package/src/common/test/index.ts +0 -2
- package/src/common/test/render.ts +0 -98
- package/src/common/test/tracer.ts +0 -359
- 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 -100
- package/src/lock/test.ts +0 -108
- package/src/project/abstractions.ts +0 -78
- package/src/project/evaluation.ts +0 -248
- package/src/project/factory.ts +0 -11
- package/src/project/index.ts +0 -3
- package/src/project/local.ts +0 -417
- package/src/pubsub/local.ts +0 -36
- package/src/pubsub/validation.ts +0 -33
- package/src/shared/utils/args.ts +0 -25
- package/src/state/abstractions.ts +0 -289
- package/src/state/encryption.ts +0 -98
- package/src/state/factory.ts +0 -20
- package/src/state/index.ts +0 -7
- package/src/state/local/backend.ts +0 -106
- package/src/state/local/collection.ts +0 -361
- package/src/state/local/index.ts +0 -2
- package/src/state/manager.ts +0 -890
- package/src/state/memory/backend.ts +0 -70
- package/src/state/memory/collection.ts +0 -270
- package/src/state/memory/index.ts +0 -2
- package/src/state/repository/index.ts +0 -2
- package/src/state/repository/repository.index.ts +0 -193
- package/src/state/repository/repository.ts +0 -507
- package/src/state/test.ts +0 -457
- /package/src/{state → database/local}/keyring.ts +0 -0
|
@@ -1,614 +1,391 @@
|
|
|
1
|
+
import type { UnitWorker } from "@highstate/contract"
|
|
2
|
+
import type { Worker, WorkerVersion } from "../database"
|
|
3
|
+
import type { PubSubManager } from "../pubsub"
|
|
1
4
|
import type { WorkerManager } from "../worker"
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
5
|
+
import { randomBytes } from "node:crypto"
|
|
6
|
+
import { createId } from "@paralleldrive/cuid2"
|
|
7
|
+
import { describe, vi } from "vitest"
|
|
8
|
+
import { extractDigestFromImage } from "../shared"
|
|
9
|
+
import { test } from "../test-utils"
|
|
7
10
|
import { WorkerService } from "./worker"
|
|
8
11
|
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
"add new unit registration when other exists",
|
|
47
|
-
async ({ tracer, stateManager, random, workerService }) => {
|
|
48
|
-
tracer.setPhase("arrange")
|
|
49
|
-
|
|
50
|
-
const existingWorker: Worker = {
|
|
51
|
-
id: random.uuidv7(),
|
|
52
|
-
meta: {},
|
|
53
|
-
image: image2V1,
|
|
54
|
-
apiKeyId: random.uuidv7(),
|
|
55
|
-
failedStartAttempts: 5,
|
|
56
|
-
status: "starting",
|
|
57
|
-
identity: getWorkerIdentity(image2V1),
|
|
58
|
-
serviceAccountId: random.uuidv7(),
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const existingRegistration: WorkerUnitRegistration = {
|
|
62
|
-
id: random.uuidv7(),
|
|
63
|
-
meta: {},
|
|
64
|
-
workerId: existingWorker.id,
|
|
65
|
-
image: image2V1,
|
|
66
|
-
instanceId: "test",
|
|
67
|
-
params: {},
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
await stateManager.getWorkerRepository("test").putItem(existingWorker)
|
|
71
|
-
await stateManager.getWorkerRegistrationRepository("test").putItem(existingRegistration)
|
|
72
|
-
|
|
73
|
-
tracer.setPhase("act")
|
|
74
|
-
|
|
75
|
-
await workerService.updateUnitRegistrations(
|
|
76
|
-
"test",
|
|
77
|
-
"test",
|
|
78
|
-
{
|
|
79
|
-
other: existingRegistration.id,
|
|
12
|
+
const workerTest = test.extend<{
|
|
13
|
+
workerService: WorkerService
|
|
14
|
+
|
|
15
|
+
createWorker(): Promise<Worker>
|
|
16
|
+
|
|
17
|
+
createWorkerVersion: (
|
|
18
|
+
worker: Worker,
|
|
19
|
+
overrides?: Pick<Partial<WorkerVersion>, "digest">,
|
|
20
|
+
) => Promise<WorkerVersion>
|
|
21
|
+
|
|
22
|
+
createMockUnitWorker: (overrides?: Partial<UnitWorker>) => UnitWorker
|
|
23
|
+
}>({
|
|
24
|
+
workerService: async ({ database, logger }, use) => {
|
|
25
|
+
const workerManager = vi.mockObject({ syncWorkers: vi.fn() } as unknown as WorkerManager)
|
|
26
|
+
|
|
27
|
+
const workerService = new WorkerService(
|
|
28
|
+
database,
|
|
29
|
+
workerManager,
|
|
30
|
+
vi.mockObject({ subscribe: vi.fn(), publish: vi.fn() } as unknown as PubSubManager),
|
|
31
|
+
logger.child({ service: "WorkerService" }),
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
await use(workerService)
|
|
35
|
+
},
|
|
36
|
+
|
|
37
|
+
createWorker: async ({ projectDatabase }, use) => {
|
|
38
|
+
const createWorker = async () => {
|
|
39
|
+
return await projectDatabase.worker.create({
|
|
40
|
+
data: {
|
|
41
|
+
identity: `ghcr.io/org/${createId()}`,
|
|
42
|
+
serviceAccount: {
|
|
43
|
+
create: {
|
|
44
|
+
meta: {
|
|
45
|
+
title: "Test Worker Service Account",
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
},
|
|
80
49
|
},
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
50
|
+
})
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
await use(createWorker)
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
createWorkerVersion: async ({ projectDatabase }, use) => {
|
|
57
|
+
const createWorkerVersion = async (
|
|
58
|
+
worker: Worker,
|
|
59
|
+
overrides: Pick<Partial<WorkerVersion>, "digest"> = {},
|
|
60
|
+
) => {
|
|
61
|
+
return await projectDatabase.workerVersion.create({
|
|
62
|
+
data: {
|
|
63
|
+
worker: { connect: worker },
|
|
64
|
+
digest: createId(),
|
|
65
|
+
meta: {
|
|
66
|
+
title: "Test Worker Version",
|
|
67
|
+
description: "Test worker version for testing purposes",
|
|
86
68
|
},
|
|
87
|
-
{
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
69
|
+
apiKey: {
|
|
70
|
+
create: {
|
|
71
|
+
meta: {
|
|
72
|
+
title: "Test Worker API Key",
|
|
73
|
+
},
|
|
74
|
+
serviceAccountId: worker.serviceAccountId,
|
|
75
|
+
token: createId(),
|
|
76
|
+
},
|
|
92
77
|
},
|
|
93
|
-
|
|
94
|
-
)
|
|
95
|
-
},
|
|
96
|
-
)
|
|
97
|
-
|
|
98
|
-
test.concurrent(
|
|
99
|
-
"no-op when no changes",
|
|
100
|
-
async ({ tracer, stateManager, random, workerService }) => {
|
|
101
|
-
tracer.setPhase("arrange")
|
|
102
|
-
|
|
103
|
-
const existingWorker: Worker = {
|
|
104
|
-
id: random.uuidv7(),
|
|
105
|
-
meta: {},
|
|
106
|
-
image: image1V1,
|
|
107
|
-
apiKeyId: random.uuidv7(),
|
|
108
|
-
failedStartAttempts: 5,
|
|
109
|
-
status: "starting",
|
|
110
|
-
identity: getWorkerIdentity(image1V1),
|
|
111
|
-
serviceAccountId: random.uuidv7(),
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
const existingRegistration: WorkerUnitRegistration = {
|
|
115
|
-
id: random.uuidv7(),
|
|
116
|
-
meta: {},
|
|
117
|
-
workerId: existingWorker.id,
|
|
118
|
-
image: image1V1,
|
|
119
|
-
instanceId: "test",
|
|
120
|
-
params: {},
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
await stateManager.getWorkerRepository("test").putItem(existingWorker)
|
|
124
|
-
await stateManager.getWorkerRegistrationRepository("test").putItem(existingRegistration)
|
|
125
|
-
|
|
126
|
-
tracer.setPhase("act")
|
|
127
|
-
|
|
128
|
-
await workerService.updateUnitRegistrations(
|
|
129
|
-
"test",
|
|
130
|
-
"test",
|
|
131
|
-
{
|
|
132
|
-
worker: existingRegistration.id,
|
|
78
|
+
...overrides,
|
|
133
79
|
},
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
80
|
+
})
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
await use(createWorkerVersion)
|
|
84
|
+
},
|
|
85
|
+
|
|
86
|
+
createMockUnitWorker: async ({}, use) => {
|
|
87
|
+
const createMockUnitWorker = (overrides: Partial<UnitWorker> = {}): UnitWorker => ({
|
|
88
|
+
name: "test-worker",
|
|
89
|
+
image: `ghcr.io/org/${createId()}@sha256:${randomBytes(32).toString("hex")}`,
|
|
90
|
+
params: { key: "value" },
|
|
91
|
+
...overrides,
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
await use(createMockUnitWorker)
|
|
95
|
+
},
|
|
96
|
+
})
|
|
144
97
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
id
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
"test",
|
|
177
|
-
"test",
|
|
178
|
-
{
|
|
179
|
-
worker: existingRegistration.id,
|
|
180
|
-
},
|
|
181
|
-
[
|
|
182
|
-
{
|
|
183
|
-
name: "worker",
|
|
184
|
-
image: image1V1,
|
|
185
|
-
params: { foo: "bar" }, // changed params
|
|
186
|
-
},
|
|
187
|
-
],
|
|
188
|
-
)
|
|
98
|
+
describe("updateUnitRegistrations", () => {
|
|
99
|
+
workerTest(
|
|
100
|
+
"creates new worker registrations for unit workers",
|
|
101
|
+
async ({
|
|
102
|
+
workerService,
|
|
103
|
+
project,
|
|
104
|
+
projectDatabase,
|
|
105
|
+
createInstanceState,
|
|
106
|
+
createMockUnitWorker,
|
|
107
|
+
expect,
|
|
108
|
+
}) => {
|
|
109
|
+
// arrange
|
|
110
|
+
const unitWorker = createMockUnitWorker()
|
|
111
|
+
const instance = await createInstanceState(project.id)
|
|
112
|
+
|
|
113
|
+
// act
|
|
114
|
+
await projectDatabase.$transaction(async tx => {
|
|
115
|
+
await workerService.updateUnitRegistrations(tx, project.id, instance.id, [unitWorker])
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
// assert
|
|
119
|
+
const registrations = await projectDatabase.workerUnitRegistration.findMany({
|
|
120
|
+
where: { stateId: instance.id },
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
// check that the registration was created with the correct data
|
|
124
|
+
expect(registrations).toHaveLength(1)
|
|
125
|
+
expect(registrations[0].name).toBe(unitWorker.name)
|
|
126
|
+
expect(registrations[0].params).toEqual(unitWorker.params)
|
|
127
|
+
expect(registrations[0].workerVersionId).toBeDefined()
|
|
128
|
+
expect(registrations[0].stateId).toBe(instance.id)
|
|
189
129
|
},
|
|
190
130
|
)
|
|
191
131
|
|
|
192
|
-
|
|
193
|
-
"
|
|
194
|
-
async ({
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
await workerService.updateUnitRegistrations(
|
|
223
|
-
"test",
|
|
224
|
-
"test",
|
|
225
|
-
{
|
|
226
|
-
worker: existingRegistration.id,
|
|
132
|
+
workerTest(
|
|
133
|
+
"updates existing worker registrations with new params",
|
|
134
|
+
async ({
|
|
135
|
+
workerService,
|
|
136
|
+
project,
|
|
137
|
+
projectDatabase,
|
|
138
|
+
createInstanceState,
|
|
139
|
+
createWorker,
|
|
140
|
+
createWorkerVersion,
|
|
141
|
+
createMockUnitWorker,
|
|
142
|
+
expect,
|
|
143
|
+
}) => {
|
|
144
|
+
// arrange
|
|
145
|
+
const unitWorker = createMockUnitWorker({ params: { key: "newValue" } })
|
|
146
|
+
const instance = await createInstanceState(project.id)
|
|
147
|
+
|
|
148
|
+
// create initial worker and version
|
|
149
|
+
const worker = await createWorker()
|
|
150
|
+
const workerVersion = await createWorkerVersion(worker, {
|
|
151
|
+
digest: extractDigestFromImage(unitWorker.image),
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
// create an initial registration
|
|
155
|
+
await projectDatabase.workerUnitRegistration.create({
|
|
156
|
+
data: {
|
|
157
|
+
stateId: instance.id,
|
|
158
|
+
name: unitWorker.name,
|
|
159
|
+
params: { key: "oldValue" },
|
|
160
|
+
workerVersionId: workerVersion.id,
|
|
227
161
|
},
|
|
228
|
-
|
|
229
|
-
{
|
|
230
|
-
name: "worker",
|
|
231
|
-
image: image1V2, // changed image version
|
|
232
|
-
params: {},
|
|
233
|
-
},
|
|
234
|
-
],
|
|
235
|
-
)
|
|
236
|
-
},
|
|
237
|
-
)
|
|
162
|
+
})
|
|
238
163
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
const existingWorker: Worker = {
|
|
245
|
-
id: random.uuidv7(),
|
|
246
|
-
meta: {},
|
|
247
|
-
image: image1V1,
|
|
248
|
-
apiKeyId: random.uuidv7(),
|
|
249
|
-
failedStartAttempts: 5,
|
|
250
|
-
status: "starting",
|
|
251
|
-
identity: getWorkerIdentity(image1V1),
|
|
252
|
-
serviceAccountId: random.uuidv7(),
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
const existingRegistration: WorkerUnitRegistration = {
|
|
256
|
-
id: random.uuidv7(),
|
|
257
|
-
meta: {},
|
|
258
|
-
workerId: existingWorker.id,
|
|
259
|
-
image: image1V1,
|
|
260
|
-
instanceId: "test",
|
|
261
|
-
params: {},
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
await stateManager.getWorkerRepository("test").putItem(existingWorker)
|
|
265
|
-
await stateManager.getWorkerRegistrationRepository("test").putItem(existingRegistration)
|
|
266
|
-
|
|
267
|
-
tracer.setPhase("act")
|
|
268
|
-
|
|
269
|
-
await workerService.updateUnitRegistrations(
|
|
270
|
-
"test",
|
|
271
|
-
"test",
|
|
272
|
-
{
|
|
273
|
-
worker: existingRegistration.id,
|
|
274
|
-
},
|
|
275
|
-
[
|
|
276
|
-
{
|
|
277
|
-
name: "worker",
|
|
278
|
-
image: image2V1, // changed image
|
|
279
|
-
params: {},
|
|
280
|
-
},
|
|
281
|
-
],
|
|
282
|
-
)
|
|
283
|
-
},
|
|
284
|
-
)
|
|
164
|
+
// act
|
|
165
|
+
await projectDatabase.$transaction(async tx => {
|
|
166
|
+
await workerService.updateUnitRegistrations(tx, project.id, instance.id, [unitWorker])
|
|
167
|
+
})
|
|
285
168
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
const existingWorker: Worker = {
|
|
292
|
-
id: random.uuidv7(),
|
|
293
|
-
meta: {},
|
|
294
|
-
image: image1V1,
|
|
295
|
-
apiKeyId: random.uuidv7(),
|
|
296
|
-
failedStartAttempts: 5,
|
|
297
|
-
status: "starting",
|
|
298
|
-
identity: getWorkerIdentity(image1V1),
|
|
299
|
-
serviceAccountId: random.uuidv7(),
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
const existingRegistration: WorkerUnitRegistration = {
|
|
303
|
-
id: random.uuidv7(),
|
|
304
|
-
meta: {},
|
|
305
|
-
workerId: existingWorker.id,
|
|
306
|
-
image: image1V1,
|
|
307
|
-
instanceId: "test",
|
|
308
|
-
params: {},
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
await stateManager.getWorkerRepository("test").putItem(existingWorker)
|
|
312
|
-
await stateManager.getWorkerRegistrationRepository("test").putItem(existingRegistration)
|
|
313
|
-
|
|
314
|
-
tracer.setPhase("act")
|
|
315
|
-
|
|
316
|
-
// remove the unit worker by not including it in the list
|
|
317
|
-
await workerService.updateUnitRegistrations(
|
|
318
|
-
"test",
|
|
319
|
-
"test",
|
|
320
|
-
{
|
|
321
|
-
worker: existingRegistration.id,
|
|
322
|
-
},
|
|
323
|
-
[], // empty list means remove all registrations
|
|
324
|
-
)
|
|
325
|
-
},
|
|
326
|
-
)
|
|
169
|
+
// assert
|
|
170
|
+
const updatedRegistration = await projectDatabase.workerUnitRegistration.findFirst({
|
|
171
|
+
where: { stateId: instance.id, name: unitWorker.name },
|
|
172
|
+
})
|
|
327
173
|
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
tracer.setPhase("arrange")
|
|
332
|
-
|
|
333
|
-
const existingWorker1: Worker = {
|
|
334
|
-
id: random.uuidv7(),
|
|
335
|
-
meta: {},
|
|
336
|
-
image: image1V1,
|
|
337
|
-
apiKeyId: random.uuidv7(),
|
|
338
|
-
failedStartAttempts: 5,
|
|
339
|
-
status: "starting",
|
|
340
|
-
identity: getWorkerIdentity(image1V1),
|
|
341
|
-
serviceAccountId: random.uuidv7(),
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
const existingWorker2: Worker = {
|
|
345
|
-
id: random.uuidv7(),
|
|
346
|
-
meta: {},
|
|
347
|
-
image: image2V1,
|
|
348
|
-
apiKeyId: random.uuidv7(),
|
|
349
|
-
failedStartAttempts: 5,
|
|
350
|
-
status: "starting",
|
|
351
|
-
identity: getWorkerIdentity(image2V1),
|
|
352
|
-
serviceAccountId: random.uuidv7(),
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
const existingRegistration1: WorkerUnitRegistration = {
|
|
356
|
-
id: random.uuidv7(),
|
|
357
|
-
meta: {},
|
|
358
|
-
workerId: existingWorker1.id,
|
|
359
|
-
image: image1V1,
|
|
360
|
-
instanceId: "test",
|
|
361
|
-
params: {},
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
const existingRegistration2: WorkerUnitRegistration = {
|
|
365
|
-
id: random.uuidv7(),
|
|
366
|
-
meta: {},
|
|
367
|
-
workerId: existingWorker2.id,
|
|
368
|
-
image: image2V1,
|
|
369
|
-
instanceId: "test",
|
|
370
|
-
params: {},
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
await stateManager.getWorkerRepository("test").putItem(existingWorker1)
|
|
374
|
-
await stateManager.getWorkerRepository("test").putItem(existingWorker2)
|
|
375
|
-
await stateManager.getWorkerRegistrationRepository("test").putItem(existingRegistration1)
|
|
376
|
-
await stateManager.getWorkerRegistrationRepository("test").putItem(existingRegistration2)
|
|
377
|
-
|
|
378
|
-
tracer.setPhase("act")
|
|
379
|
-
|
|
380
|
-
// keep only worker1, remove worker2
|
|
381
|
-
await workerService.updateUnitRegistrations(
|
|
382
|
-
"test",
|
|
383
|
-
"test",
|
|
384
|
-
{
|
|
385
|
-
worker1: existingRegistration1.id,
|
|
386
|
-
worker2: existingRegistration2.id,
|
|
387
|
-
},
|
|
388
|
-
[
|
|
389
|
-
{
|
|
390
|
-
name: "worker1",
|
|
391
|
-
image: image1V1,
|
|
392
|
-
params: {},
|
|
393
|
-
},
|
|
394
|
-
// worker2 is removed by not being in the list
|
|
395
|
-
],
|
|
396
|
-
)
|
|
174
|
+
expect(updatedRegistration).toBeDefined()
|
|
175
|
+
expect(updatedRegistration?.params).toEqual(unitWorker.params)
|
|
176
|
+
expect(updatedRegistration?.workerVersionId).toBe(workerVersion.id)
|
|
397
177
|
},
|
|
398
178
|
)
|
|
399
179
|
|
|
400
|
-
|
|
401
|
-
"
|
|
402
|
-
async ({
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
//
|
|
420
|
-
const
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
const existingRegistration: WorkerUnitRegistration = {
|
|
432
|
-
id: random.uuidv7(),
|
|
433
|
-
meta: {},
|
|
434
|
-
workerId: existingWorker1.id,
|
|
435
|
-
image: image1V1,
|
|
436
|
-
instanceId: "test",
|
|
437
|
-
params: {},
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
await stateManager.getWorkerRepository("test").putItem(existingWorker1)
|
|
441
|
-
await stateManager.getWorkerRepository("test").putItem(existingWorker2)
|
|
442
|
-
await stateManager.getWorkerRegistrationRepository("test").putItem(existingRegistration)
|
|
443
|
-
|
|
444
|
-
tracer.setPhase("act")
|
|
445
|
-
|
|
446
|
-
// request v2 image, should reuse existing worker2 and service account
|
|
447
|
-
await workerService.updateUnitRegistrations(
|
|
448
|
-
"test",
|
|
449
|
-
"test",
|
|
450
|
-
{
|
|
451
|
-
worker: existingRegistration.id,
|
|
180
|
+
workerTest(
|
|
181
|
+
"creates new worker version while keeping existing one when both are in use",
|
|
182
|
+
async ({
|
|
183
|
+
workerService,
|
|
184
|
+
project,
|
|
185
|
+
projectDatabase,
|
|
186
|
+
createInstanceState,
|
|
187
|
+
createWorker,
|
|
188
|
+
createWorkerVersion,
|
|
189
|
+
createMockUnitWorker,
|
|
190
|
+
expect,
|
|
191
|
+
}) => {
|
|
192
|
+
// arrange
|
|
193
|
+
const oldDigest = randomBytes(32).toString("hex")
|
|
194
|
+
const newDigest = randomBytes(32).toString("hex")
|
|
195
|
+
|
|
196
|
+
const worker = await createWorker()
|
|
197
|
+
const oldWorkerVersion = await createWorkerVersion(worker, { digest: oldDigest })
|
|
198
|
+
|
|
199
|
+
// create two instances, both using the same worker version initially
|
|
200
|
+
const instance1 = await createInstanceState(project.id)
|
|
201
|
+
const instance2 = await createInstanceState(project.id)
|
|
202
|
+
|
|
203
|
+
// create registrations for both instances using the old version
|
|
204
|
+
await projectDatabase.workerUnitRegistration.create({
|
|
205
|
+
data: {
|
|
206
|
+
stateId: instance1.id,
|
|
207
|
+
name: "test-worker",
|
|
208
|
+
params: { key: "value1" },
|
|
209
|
+
workerVersionId: oldWorkerVersion.id,
|
|
452
210
|
},
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
211
|
+
})
|
|
212
|
+
|
|
213
|
+
await projectDatabase.workerUnitRegistration.create({
|
|
214
|
+
data: {
|
|
215
|
+
stateId: instance2.id,
|
|
216
|
+
name: "test-worker",
|
|
217
|
+
params: { key: "value2" },
|
|
218
|
+
workerVersionId: oldWorkerVersion.id,
|
|
219
|
+
},
|
|
220
|
+
})
|
|
221
|
+
|
|
222
|
+
// act - update only instance1 to use new worker version
|
|
223
|
+
const newUnitWorker = createMockUnitWorker({
|
|
224
|
+
image: `${worker.identity}@sha256:${newDigest}`,
|
|
225
|
+
params: { key: "newValue" },
|
|
226
|
+
})
|
|
227
|
+
|
|
228
|
+
await projectDatabase.$transaction(async tx => {
|
|
229
|
+
await workerService.updateUnitRegistrations(tx, project.id, instance1.id, [newUnitWorker])
|
|
230
|
+
})
|
|
231
|
+
|
|
232
|
+
// assert
|
|
233
|
+
const instance1Registration = await projectDatabase.workerUnitRegistration.findFirst({
|
|
234
|
+
where: { stateId: instance1.id, name: "test-worker" },
|
|
235
|
+
include: { workerVersion: true },
|
|
236
|
+
})
|
|
237
|
+
|
|
238
|
+
const instance2Registration = await projectDatabase.workerUnitRegistration.findFirst({
|
|
239
|
+
where: { stateId: instance2.id, name: "test-worker" },
|
|
240
|
+
include: { workerVersion: true },
|
|
241
|
+
})
|
|
242
|
+
|
|
243
|
+
// verify instance1 now uses new version
|
|
244
|
+
expect(instance1Registration?.workerVersion.digest).toBe(newDigest)
|
|
245
|
+
expect(instance1Registration?.params).toEqual({ key: "newValue" })
|
|
246
|
+
|
|
247
|
+
// verify instance2 still uses old version
|
|
248
|
+
expect(instance2Registration?.workerVersion.digest).toBe(oldDigest)
|
|
249
|
+
expect(instance2Registration?.params).toEqual({ key: "value2" })
|
|
250
|
+
|
|
251
|
+
// verify both worker versions still exist (no cleanup since both are in use)
|
|
252
|
+
const allVersions = await projectDatabase.workerVersion.findMany({
|
|
253
|
+
where: { workerId: worker.id },
|
|
254
|
+
})
|
|
255
|
+
expect(allVersions).toHaveLength(2)
|
|
256
|
+
expect(allVersions.map(v => v.digest).sort()).toEqual([oldDigest, newDigest].sort())
|
|
461
257
|
},
|
|
462
258
|
)
|
|
463
259
|
|
|
464
|
-
|
|
465
|
-
"worker
|
|
466
|
-
async ({
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
const
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
workerId: existingWorker.id,
|
|
493
|
-
image: image1V1,
|
|
494
|
-
instanceId: "test2", // different instance
|
|
495
|
-
params: {},
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
await stateManager.getWorkerRepository("test").putItem(existingWorker)
|
|
499
|
-
await stateManager.getWorkerRegistrationRepository("test").putItem(existingRegistration1)
|
|
500
|
-
await stateManager.getWorkerRegistrationRepository("test").putItem(existingRegistration2)
|
|
501
|
-
|
|
502
|
-
// add both registrations to the worker's index
|
|
503
|
-
await stateManager
|
|
504
|
-
.getWorkerRegistrationIndexRepository("test", existingWorker.id)
|
|
505
|
-
.indexRepository.put(existingRegistration1.id, "")
|
|
506
|
-
await stateManager
|
|
507
|
-
.getWorkerRegistrationIndexRepository("test", existingWorker.id)
|
|
508
|
-
.indexRepository.put(existingRegistration2.id, "")
|
|
509
|
-
|
|
510
|
-
tracer.setPhase("act")
|
|
511
|
-
|
|
512
|
-
// remove registration1, but registration2 still exists
|
|
513
|
-
await workerService.updateUnitRegistrations(
|
|
514
|
-
"test",
|
|
515
|
-
"test",
|
|
516
|
-
{
|
|
517
|
-
worker1: existingRegistration1.id,
|
|
518
|
-
// worker2 not included in existing registrations for this instance
|
|
260
|
+
workerTest(
|
|
261
|
+
"creates new worker version and deletes old unused one",
|
|
262
|
+
async ({
|
|
263
|
+
workerService,
|
|
264
|
+
project,
|
|
265
|
+
projectDatabase,
|
|
266
|
+
createInstanceState,
|
|
267
|
+
createWorker,
|
|
268
|
+
createWorkerVersion,
|
|
269
|
+
createMockUnitWorker,
|
|
270
|
+
expect,
|
|
271
|
+
}) => {
|
|
272
|
+
// arrange
|
|
273
|
+
const oldDigest = randomBytes(32).toString("hex")
|
|
274
|
+
const newDigest = randomBytes(32).toString("hex")
|
|
275
|
+
|
|
276
|
+
const worker = await createWorker()
|
|
277
|
+
const oldWorkerVersion = await createWorkerVersion(worker, { digest: oldDigest })
|
|
278
|
+
|
|
279
|
+
const instance = await createInstanceState(project.id)
|
|
280
|
+
|
|
281
|
+
// create registration using old version
|
|
282
|
+
await projectDatabase.workerUnitRegistration.create({
|
|
283
|
+
data: {
|
|
284
|
+
stateId: instance.id,
|
|
285
|
+
name: "test-worker",
|
|
286
|
+
params: { key: "oldValue" },
|
|
287
|
+
workerVersionId: oldWorkerVersion.id,
|
|
519
288
|
},
|
|
520
|
-
|
|
521
|
-
|
|
289
|
+
})
|
|
290
|
+
|
|
291
|
+
// act - update to use new worker version
|
|
292
|
+
const newUnitWorker = createMockUnitWorker({
|
|
293
|
+
image: `${worker.identity}@sha256:${newDigest}`,
|
|
294
|
+
params: { key: "newValue" },
|
|
295
|
+
})
|
|
296
|
+
|
|
297
|
+
await projectDatabase.$transaction(async tx => {
|
|
298
|
+
await workerService.updateUnitRegistrations(tx, project.id, instance.id, [newUnitWorker])
|
|
299
|
+
})
|
|
300
|
+
|
|
301
|
+
// assert
|
|
302
|
+
const registration = await projectDatabase.workerUnitRegistration.findFirst({
|
|
303
|
+
where: { stateId: instance.id, name: "test-worker" },
|
|
304
|
+
include: { workerVersion: true },
|
|
305
|
+
})
|
|
306
|
+
|
|
307
|
+
// verify registration now uses new version
|
|
308
|
+
expect(registration?.workerVersion.digest).toBe(newDigest)
|
|
309
|
+
expect(registration?.params).toEqual({ key: "newValue" })
|
|
310
|
+
|
|
311
|
+
// verify old version was cleaned up
|
|
312
|
+
const oldVersion = await projectDatabase.workerVersion.findFirst({
|
|
313
|
+
where: { digest: oldDigest, workerId: worker.id },
|
|
314
|
+
})
|
|
315
|
+
expect(oldVersion).toBeNull()
|
|
316
|
+
|
|
317
|
+
// verify new version exists
|
|
318
|
+
const newVersion = await projectDatabase.workerVersion.findFirst({
|
|
319
|
+
where: { digest: newDigest, workerId: worker.id },
|
|
320
|
+
})
|
|
321
|
+
expect(newVersion).toBeDefined()
|
|
522
322
|
},
|
|
523
323
|
)
|
|
524
324
|
|
|
525
|
-
|
|
526
|
-
"
|
|
527
|
-
async ({
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
const
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
await
|
|
552
|
-
|
|
553
|
-
tracer.setPhase("act")
|
|
554
|
-
|
|
555
|
-
await workerService.updateUnitRegistrations(
|
|
556
|
-
"test",
|
|
557
|
-
"test",
|
|
558
|
-
{
|
|
559
|
-
worker: existingRegistration.id,
|
|
560
|
-
},
|
|
561
|
-
[
|
|
325
|
+
workerTest(
|
|
326
|
+
"removes all registrations and cleans up unused worker versions when unit workers list is empty",
|
|
327
|
+
async ({
|
|
328
|
+
workerService,
|
|
329
|
+
project,
|
|
330
|
+
projectDatabase,
|
|
331
|
+
createInstanceState,
|
|
332
|
+
createWorker,
|
|
333
|
+
createWorkerVersion,
|
|
334
|
+
expect,
|
|
335
|
+
}) => {
|
|
336
|
+
// arrange
|
|
337
|
+
const worker1 = await createWorker()
|
|
338
|
+
const worker2 = await createWorker()
|
|
339
|
+
|
|
340
|
+
const digest1 = randomBytes(32).toString("hex")
|
|
341
|
+
const digest2 = randomBytes(32).toString("hex")
|
|
342
|
+
|
|
343
|
+
const version1 = await createWorkerVersion(worker1, { digest: digest1 })
|
|
344
|
+
const version2 = await createWorkerVersion(worker2, { digest: digest2 })
|
|
345
|
+
|
|
346
|
+
const instance = await createInstanceState(project.id)
|
|
347
|
+
|
|
348
|
+
console.log(instance.id, version1.id, version2.id)
|
|
349
|
+
|
|
350
|
+
// create multiple registrations
|
|
351
|
+
await projectDatabase.workerUnitRegistration.createMany({
|
|
352
|
+
data: [
|
|
562
353
|
{
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
params: {
|
|
354
|
+
stateId: instance.id,
|
|
355
|
+
name: "worker1",
|
|
356
|
+
params: { key: "value1" },
|
|
357
|
+
workerVersionId: version1.id,
|
|
566
358
|
},
|
|
567
|
-
],
|
|
568
|
-
)
|
|
569
|
-
},
|
|
570
|
-
)
|
|
571
|
-
|
|
572
|
-
test.concurrent(
|
|
573
|
-
"handle nonexistent registration id gracefully",
|
|
574
|
-
async ({ tracer, workerService }) => {
|
|
575
|
-
tracer.setPhase("act")
|
|
576
|
-
|
|
577
|
-
// provide a nonexistent registration ID
|
|
578
|
-
await workerService.updateUnitRegistrations(
|
|
579
|
-
"test",
|
|
580
|
-
"test",
|
|
581
|
-
{
|
|
582
|
-
worker: "nonexistent-registration-id",
|
|
583
|
-
},
|
|
584
|
-
[
|
|
585
359
|
{
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
params: {},
|
|
360
|
+
stateId: instance.id,
|
|
361
|
+
name: "worker2",
|
|
362
|
+
params: { key: "value2" },
|
|
363
|
+
workerVersionId: version2.id,
|
|
589
364
|
},
|
|
590
365
|
],
|
|
591
|
-
)
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
{
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
366
|
+
})
|
|
367
|
+
|
|
368
|
+
// act - update with empty workers list
|
|
369
|
+
await projectDatabase.$transaction(async tx => {
|
|
370
|
+
await workerService.updateUnitRegistrations(tx, project.id, instance.id, [])
|
|
371
|
+
})
|
|
372
|
+
|
|
373
|
+
// assert
|
|
374
|
+
const remainingRegistrations = await projectDatabase.workerUnitRegistration.findMany({
|
|
375
|
+
where: { stateId: instance.id },
|
|
376
|
+
})
|
|
377
|
+
expect(remainingRegistrations).toHaveLength(0)
|
|
378
|
+
|
|
379
|
+
// verify unused worker versions were cleaned up
|
|
380
|
+
const remainingVersions = await projectDatabase.workerVersion.findMany({
|
|
381
|
+
where: {
|
|
382
|
+
OR: [
|
|
383
|
+
{ digest: digest1, workerId: worker1.id },
|
|
384
|
+
{ digest: digest2, workerId: worker2.id },
|
|
385
|
+
],
|
|
610
386
|
},
|
|
611
|
-
|
|
387
|
+
})
|
|
388
|
+
expect(remainingVersions).toHaveLength(0)
|
|
612
389
|
},
|
|
613
390
|
)
|
|
614
391
|
})
|