@shipfox/api-runners 4.0.0 → 6.0.0
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/.turbo/turbo-build.log +6 -6
- package/CHANGELOG.md +83 -0
- package/dist/config.d.ts +5 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +53 -6
- package/dist/config.js.map +1 -1
- package/dist/core/capacity-assignments.d.ts +7 -0
- package/dist/core/capacity-assignments.d.ts.map +1 -0
- package/dist/core/capacity-assignments.js +6 -0
- package/dist/core/capacity-assignments.js.map +1 -0
- package/dist/core/demand.d.ts +6 -6
- package/dist/core/demand.d.ts.map +1 -1
- package/dist/core/demand.js +10 -10
- package/dist/core/demand.js.map +1 -1
- package/dist/core/entities/capacity-assignment.d.ts +9 -0
- package/dist/core/entities/capacity-assignment.d.ts.map +1 -0
- package/dist/core/entities/capacity-assignment.js +3 -0
- package/dist/core/entities/capacity-assignment.js.map +1 -0
- package/dist/core/entities/ephemeral-registration-token.d.ts +1 -1
- package/dist/core/entities/ephemeral-registration-token.d.ts.map +1 -1
- package/dist/core/entities/ephemeral-registration-token.js.map +1 -1
- package/dist/core/entities/provisioner-capability-snapshot.d.ts +13 -0
- package/dist/core/entities/provisioner-capability-snapshot.d.ts.map +1 -0
- package/dist/core/entities/provisioner-capability-snapshot.js +3 -0
- package/dist/core/entities/provisioner-capability-snapshot.js.map +1 -0
- package/dist/core/entities/provisioner-token.d.ts +10 -2
- package/dist/core/entities/provisioner-token.d.ts.map +1 -1
- package/dist/core/entities/provisioner-token.js.map +1 -1
- package/dist/core/entities/{provisioned-runner.d.ts → runner-instance.d.ts} +6 -6
- package/dist/core/entities/runner-instance.d.ts.map +1 -0
- package/dist/core/entities/runner-instance.js +3 -0
- package/dist/core/entities/runner-instance.js.map +1 -0
- package/dist/core/entities/runner-session.d.ts +4 -2
- package/dist/core/entities/runner-session.d.ts.map +1 -1
- package/dist/core/entities/runner-session.js.map +1 -1
- package/dist/core/ephemeral-registration-tokens.d.ts +5 -5
- package/dist/core/ephemeral-registration-tokens.d.ts.map +1 -1
- package/dist/core/ephemeral-registration-tokens.js +12 -12
- package/dist/core/ephemeral-registration-tokens.js.map +1 -1
- package/dist/core/errors.d.ts +16 -4
- package/dist/core/errors.d.ts.map +1 -1
- package/dist/core/errors.js +22 -4
- package/dist/core/errors.js.map +1 -1
- package/dist/core/index.d.ts +10 -4
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +6 -2
- package/dist/core/index.js.map +1 -1
- package/dist/core/job-executions.d.ts +2 -0
- package/dist/core/job-executions.d.ts.map +1 -1
- package/dist/core/job-executions.js +1 -2
- package/dist/core/job-executions.js.map +1 -1
- package/dist/core/maintenance.d.ts +1 -1
- package/dist/core/maintenance.d.ts.map +1 -1
- package/dist/core/maintenance.js +5 -5
- package/dist/core/maintenance.js.map +1 -1
- package/dist/core/provisioner-capability-snapshots.d.ts +5 -0
- package/dist/core/provisioner-capability-snapshots.d.ts.map +1 -0
- package/dist/core/provisioner-capability-snapshots.js +10 -0
- package/dist/core/provisioner-capability-snapshots.js.map +1 -0
- package/dist/core/provisioner-tokens.d.ts +10 -0
- package/dist/core/provisioner-tokens.d.ts.map +1 -1
- package/dist/core/provisioner-tokens.js +23 -1
- package/dist/core/provisioner-tokens.js.map +1 -1
- package/dist/core/rate-limit.d.ts.map +1 -1
- package/dist/core/rate-limit.js +2 -7
- package/dist/core/rate-limit.js.map +1 -1
- package/dist/core/runner-activation.d.ts +13 -0
- package/dist/core/runner-activation.d.ts.map +1 -0
- package/dist/core/runner-activation.js +36 -0
- package/dist/core/runner-activation.js.map +1 -0
- package/dist/core/runner-control-sessions.d.ts +46 -0
- package/dist/core/runner-control-sessions.d.ts.map +1 -0
- package/dist/core/runner-control-sessions.js +121 -0
- package/dist/core/runner-control-sessions.js.map +1 -0
- package/dist/core/runner-instances.d.ts +79 -0
- package/dist/core/runner-instances.d.ts.map +1 -0
- package/dist/core/runner-instances.js +168 -0
- package/dist/core/runner-instances.js.map +1 -0
- package/dist/core/runner-sessions.d.ts +8 -2
- package/dist/core/runner-sessions.d.ts.map +1 -1
- package/dist/core/runner-sessions.js +8 -5
- package/dist/core/runner-sessions.js.map +1 -1
- package/dist/db/capacity-assignments.d.ts +7 -0
- package/dist/db/capacity-assignments.d.ts.map +1 -0
- package/dist/db/capacity-assignments.js +72 -0
- package/dist/db/capacity-assignments.js.map +1 -0
- package/dist/db/db.d.ts +2837 -1009
- package/dist/db/db.d.ts.map +1 -1
- package/dist/db/db.js +11 -2
- package/dist/db/db.js.map +1 -1
- package/dist/db/ephemeral-registration-tokens.d.ts +2 -2
- package/dist/db/ephemeral-registration-tokens.d.ts.map +1 -1
- package/dist/db/ephemeral-registration-tokens.js +21 -21
- package/dist/db/ephemeral-registration-tokens.js.map +1 -1
- package/dist/db/index.d.ts +7 -4
- package/dist/db/index.d.ts.map +1 -1
- package/dist/db/index.js +5 -2
- package/dist/db/index.js.map +1 -1
- package/dist/db/job-executions.d.ts +6 -6
- package/dist/db/job-executions.d.ts.map +1 -1
- package/dist/db/job-executions.js +20 -19
- package/dist/db/job-executions.js.map +1 -1
- package/dist/db/provisioner-capability-snapshots.d.ts +21 -0
- package/dist/db/provisioner-capability-snapshots.d.ts.map +1 -0
- package/dist/db/provisioner-capability-snapshots.js +57 -0
- package/dist/db/provisioner-capability-snapshots.js.map +1 -0
- package/dist/db/provisioner-tokens.d.ts +7 -2
- package/dist/db/provisioner-tokens.d.ts.map +1 -1
- package/dist/db/provisioner-tokens.js +59 -10
- package/dist/db/provisioner-tokens.js.map +1 -1
- package/dist/db/reservations.d.ts +18 -0
- package/dist/db/reservations.d.ts.map +1 -1
- package/dist/db/reservations.js +88 -1
- package/dist/db/reservations.js.map +1 -1
- package/dist/db/runner-instances.d.ts +91 -0
- package/dist/db/runner-instances.d.ts.map +1 -0
- package/dist/db/runner-instances.js +511 -0
- package/dist/db/runner-instances.js.map +1 -0
- package/dist/db/runner-sessions.d.ts +5 -0
- package/dist/db/runner-sessions.d.ts.map +1 -1
- package/dist/db/runner-sessions.js +48 -2
- package/dist/db/runner-sessions.js.map +1 -1
- package/dist/db/schema/capacity-assignments.d.ts +113 -0
- package/dist/db/schema/capacity-assignments.d.ts.map +1 -0
- package/dist/db/schema/capacity-assignments.js +29 -0
- package/dist/db/schema/capacity-assignments.js.map +1 -0
- package/dist/db/schema/ephemeral-registration-tokens.d.ts +2 -2
- package/dist/db/schema/ephemeral-registration-tokens.js +3 -3
- package/dist/db/schema/ephemeral-registration-tokens.js.map +1 -1
- package/dist/db/schema/provisioner-capability-snapshots.d.ts +207 -0
- package/dist/db/schema/provisioner-capability-snapshots.d.ts.map +1 -0
- package/dist/db/schema/provisioner-capability-snapshots.js +38 -0
- package/dist/db/schema/provisioner-capability-snapshots.js.map +1 -0
- package/dist/db/schema/provisioner-tokens.d.ts +19 -1
- package/dist/db/schema/provisioner-tokens.d.ts.map +1 -1
- package/dist/db/schema/provisioner-tokens.js +29 -3
- package/dist/db/schema/provisioner-tokens.js.map +1 -1
- package/dist/db/schema/runner-activation-tokens.d.ts +161 -0
- package/dist/db/schema/runner-activation-tokens.d.ts.map +1 -0
- package/dist/db/schema/runner-activation-tokens.js +27 -0
- package/dist/db/schema/runner-activation-tokens.js.map +1 -0
- package/dist/db/schema/runner-control-sessions.d.ts +338 -0
- package/dist/db/schema/runner-control-sessions.d.ts.map +1 -0
- package/dist/db/schema/runner-control-sessions.js +52 -0
- package/dist/db/schema/runner-control-sessions.js.map +1 -0
- package/dist/db/schema/{provisioned-runners.d.ts → runner-instances.d.ts} +88 -34
- package/dist/db/schema/runner-instances.d.ts.map +1 -0
- package/dist/db/schema/{provisioned-runners.js → runner-instances.js} +19 -14
- package/dist/db/schema/runner-instances.js.map +1 -0
- package/dist/db/schema/runner-sessions.d.ts +39 -5
- package/dist/db/schema/runner-sessions.d.ts.map +1 -1
- package/dist/db/schema/runner-sessions.js +13 -6
- package/dist/db/schema/runner-sessions.js.map +1 -1
- package/dist/db/schema/running-job-executions.d.ts +2 -2
- package/dist/db/schema/running-job-executions.js +4 -4
- package/dist/db/schema/running-job-executions.js.map +1 -1
- package/dist/index.d.ts +7 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +45 -38
- package/dist/index.js.map +1 -1
- package/dist/installation-provisioning.d.ts +14 -0
- package/dist/installation-provisioning.d.ts.map +1 -0
- package/dist/installation-provisioning.js +7 -0
- package/dist/installation-provisioning.js.map +1 -0
- package/dist/metrics/index.d.ts +1 -1
- package/dist/metrics/index.d.ts.map +1 -1
- package/dist/metrics/index.js +1 -1
- package/dist/metrics/index.js.map +1 -1
- package/dist/metrics/instance.d.ts +11 -7
- package/dist/metrics/instance.d.ts.map +1 -1
- package/dist/metrics/instance.js +13 -7
- package/dist/metrics/instance.js.map +1 -1
- package/dist/presentation/auth/index.d.ts +1 -0
- package/dist/presentation/auth/index.d.ts.map +1 -1
- package/dist/presentation/auth/index.js +1 -0
- package/dist/presentation/auth/index.js.map +1 -1
- package/dist/presentation/auth/provisioner-token-auth.d.ts.map +1 -1
- package/dist/presentation/auth/provisioner-token-auth.js +5 -1
- package/dist/presentation/auth/provisioner-token-auth.js.map +1 -1
- package/dist/presentation/auth/runner-control-session-auth.d.ts +4 -0
- package/dist/presentation/auth/runner-control-session-auth.d.ts.map +1 -0
- package/dist/presentation/auth/runner-control-session-auth.js +29 -0
- package/dist/presentation/auth/runner-control-session-auth.js.map +1 -0
- package/dist/presentation/auth/runner-registration-token-auth.d.ts +5 -1
- package/dist/presentation/auth/runner-registration-token-auth.d.ts.map +1 -1
- package/dist/presentation/auth/runner-registration-token-auth.js +21 -1
- package/dist/presentation/auth/runner-registration-token-auth.js.map +1 -1
- package/dist/presentation/dto/index.d.ts +2 -2
- package/dist/presentation/dto/index.d.ts.map +1 -1
- package/dist/presentation/dto/index.js +2 -2
- package/dist/presentation/dto/index.js.map +1 -1
- package/dist/presentation/dto/mint-registration-tokens.d.ts +5 -3
- package/dist/presentation/dto/mint-registration-tokens.d.ts.map +1 -1
- package/dist/presentation/dto/mint-registration-tokens.js +4 -4
- package/dist/presentation/dto/mint-registration-tokens.js.map +1 -1
- package/dist/presentation/dto/poll-demand.d.ts.map +1 -1
- package/dist/presentation/dto/poll-demand.js +7 -1
- package/dist/presentation/dto/poll-demand.js.map +1 -1
- package/dist/presentation/dto/provisioner-token.d.ts +1 -0
- package/dist/presentation/dto/provisioner-token.d.ts.map +1 -1
- package/dist/presentation/dto/provisioner-token.js +5 -1
- package/dist/presentation/dto/provisioner-token.js.map +1 -1
- package/dist/presentation/dto/{provisioned-runners.d.ts → runner-instances.d.ts} +9 -9
- package/dist/presentation/dto/runner-instances.d.ts.map +1 -0
- package/dist/presentation/dto/{provisioned-runners.js → runner-instances.js} +6 -6
- package/dist/presentation/dto/runner-instances.js.map +1 -0
- package/dist/presentation/index.d.ts +2 -2
- package/dist/presentation/index.d.ts.map +1 -1
- package/dist/presentation/index.js +2 -2
- package/dist/presentation/index.js.map +1 -1
- package/dist/presentation/inter-module.d.ts +5 -0
- package/dist/presentation/inter-module.d.ts.map +1 -0
- package/dist/presentation/inter-module.js +43 -0
- package/dist/presentation/inter-module.js.map +1 -0
- package/dist/presentation/routes/assign-capacity.d.ts +2 -0
- package/dist/presentation/routes/assign-capacity.d.ts.map +1 -0
- package/dist/presentation/routes/assign-capacity.js +44 -0
- package/dist/presentation/routes/assign-capacity.js.map +1 -0
- package/dist/presentation/routes/get-provisioner-me.d.ts.map +1 -1
- package/dist/presentation/routes/get-provisioner-me.js +5 -1
- package/dist/presentation/routes/get-provisioner-me.js.map +1 -1
- package/dist/presentation/routes/heartbeat.d.ts +2 -1
- package/dist/presentation/routes/heartbeat.d.ts.map +1 -1
- package/dist/presentation/routes/heartbeat.js +60 -50
- package/dist/presentation/routes/heartbeat.js.map +1 -1
- package/dist/presentation/routes/index.d.ts +3 -1
- package/dist/presentation/routes/index.d.ts.map +1 -1
- package/dist/presentation/routes/index.js +83 -50
- package/dist/presentation/routes/index.js.map +1 -1
- package/dist/presentation/routes/mint-registration-tokens.d.ts.map +1 -1
- package/dist/presentation/routes/mint-registration-tokens.js +5 -5
- package/dist/presentation/routes/mint-registration-tokens.js.map +1 -1
- package/dist/presentation/routes/planned-capacity.d.ts +3 -0
- package/dist/presentation/routes/planned-capacity.d.ts.map +1 -0
- package/dist/presentation/routes/planned-capacity.js +54 -0
- package/dist/presentation/routes/planned-capacity.js.map +1 -0
- package/dist/presentation/routes/poll-demand.d.ts +2 -0
- package/dist/presentation/routes/poll-demand.d.ts.map +1 -1
- package/dist/presentation/routes/poll-demand.js +86 -45
- package/dist/presentation/routes/poll-demand.js.map +1 -1
- package/dist/presentation/routes/reconcile-runner-instances.d.ts +2 -0
- package/dist/presentation/routes/reconcile-runner-instances.d.ts.map +1 -0
- package/dist/presentation/routes/reconcile-runner-instances.js +27 -0
- package/dist/presentation/routes/reconcile-runner-instances.js.map +1 -0
- package/dist/presentation/routes/register.d.ts +2 -1
- package/dist/presentation/routes/register.d.ts.map +1 -1
- package/dist/presentation/routes/register.js +55 -52
- package/dist/presentation/routes/register.js.map +1 -1
- package/dist/presentation/routes/report-runner-instances.d.ts +2 -0
- package/dist/presentation/routes/report-runner-instances.d.ts.map +1 -0
- package/dist/presentation/routes/report-runner-instances.js +37 -0
- package/dist/presentation/routes/report-runner-instances.js.map +1 -0
- package/dist/presentation/routes/request-job.d.ts +2 -1
- package/dist/presentation/routes/request-job.d.ts.map +1 -1
- package/dist/presentation/routes/request-job.js +39 -36
- package/dist/presentation/routes/request-job.js.map +1 -1
- package/dist/presentation/routes/runner-enrollment.d.ts +7 -0
- package/dist/presentation/routes/runner-enrollment.d.ts.map +1 -0
- package/dist/presentation/routes/runner-enrollment.js +185 -0
- package/dist/presentation/routes/runner-enrollment.js.map +1 -0
- package/dist/temporal/activities/index.d.ts +2 -2
- package/dist/temporal/activities/index.d.ts.map +1 -1
- package/dist/temporal/activities/index.js +2 -2
- package/dist/temporal/activities/index.js.map +1 -1
- package/dist/temporal/activities/maintenance-activities.d.ts +1 -1
- package/dist/temporal/activities/maintenance-activities.d.ts.map +1 -1
- package/dist/temporal/activities/maintenance-activities.js +3 -3
- package/dist/temporal/activities/maintenance-activities.js.map +1 -1
- package/dist/temporal/workflows/index.bundle.js +3 -3
- package/dist/temporal/workflows/stuck-job-detector.js +2 -2
- package/dist/temporal/workflows/stuck-job-detector.js.map +1 -1
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/drizzle/0000_initial.sql +102 -24
- package/drizzle/meta/0000_snapshot.json +483 -63
- package/package.json +31 -36
- package/src/config.test.ts +0 -26
- package/src/config.ts +47 -6
- package/src/core/capacity-assignments.ts +10 -0
- package/src/core/demand.test.ts +29 -29
- package/src/core/demand.ts +22 -22
- package/src/core/entities/capacity-assignment.ts +8 -0
- package/src/core/entities/ephemeral-registration-token.ts +1 -1
- package/src/core/entities/provisioner-capability-snapshot.ts +12 -0
- package/src/core/entities/provisioner-token.ts +8 -2
- package/src/core/entities/{provisioned-runner.ts → runner-instance.ts} +5 -5
- package/src/core/entities/runner-session.ts +4 -2
- package/src/core/ephemeral-registration-tokens.test.ts +11 -11
- package/src/core/ephemeral-registration-tokens.ts +18 -20
- package/src/core/errors.ts +23 -4
- package/src/core/index.ts +39 -17
- package/src/core/job-executions.ts +3 -2
- package/src/core/maintenance.test.ts +13 -17
- package/src/core/maintenance.ts +5 -5
- package/src/core/provisioner-capability-snapshots.test.ts +35 -0
- package/src/core/provisioner-capability-snapshots.ts +12 -0
- package/src/core/provisioner-tokens.test.ts +20 -0
- package/src/core/provisioner-tokens.ts +33 -0
- package/src/core/rate-limit.test.ts +11 -27
- package/src/core/rate-limit.ts +3 -11
- package/src/core/runner-activation.ts +72 -0
- package/src/core/runner-control-sessions.ts +190 -0
- package/src/core/{provisioned-runners.test.ts → runner-instances.test.ts} +24 -24
- package/src/core/runner-instances.ts +310 -0
- package/src/core/runner-sessions.test.ts +112 -22
- package/src/core/runner-sessions.ts +25 -14
- package/src/db/capacity-assignments.test.ts +159 -0
- package/src/db/capacity-assignments.ts +116 -0
- package/src/db/db.ts +11 -2
- package/src/db/ephemeral-registration-tokens.test.ts +9 -9
- package/src/db/ephemeral-registration-tokens.ts +26 -26
- package/src/db/index.ts +31 -21
- package/src/db/job-executions.test.ts +13 -11
- package/src/db/job-executions.ts +33 -27
- package/src/db/provisioner-capability-snapshots.test.ts +175 -0
- package/src/db/provisioner-capability-snapshots.ts +130 -0
- package/src/db/provisioner-tokens.test.ts +139 -2
- package/src/db/provisioner-tokens.ts +123 -15
- package/src/db/reservations.test.ts +49 -0
- package/src/db/reservations.ts +146 -1
- package/src/db/{provisioned-runners.test.ts → runner-instances.test.ts} +429 -353
- package/src/db/runner-instances.ts +942 -0
- package/src/db/runner-sessions.test.ts +19 -6
- package/src/db/runner-sessions.ts +78 -2
- package/src/db/schema/capacity-assignments.ts +34 -0
- package/src/db/schema/ephemeral-registration-tokens.ts +4 -4
- package/src/db/schema/provisioner-capability-snapshots.ts +46 -0
- package/src/db/schema/provisioner-tokens.ts +33 -2
- package/src/db/schema/runner-activation-tokens.ts +22 -0
- package/src/db/schema/runner-control-sessions.ts +46 -0
- package/src/db/schema/{provisioned-runners.ts → runner-instances.ts} +26 -27
- package/src/db/schema/runner-sessions.ts +11 -7
- package/src/db/schema/running-job-executions.ts +5 -5
- package/src/index.test.ts +26 -0
- package/src/index.ts +39 -19
- package/src/installation-provisioning.ts +14 -0
- package/src/metrics/index.ts +5 -5
- package/src/metrics/instance.ts +25 -14
- package/src/presentation/auth/index.ts +4 -0
- package/src/presentation/auth/provisioner-token-auth.ts +8 -4
- package/src/presentation/auth/runner-control-session-auth.ts +31 -0
- package/src/presentation/auth/runner-registration-token-auth.ts +39 -3
- package/src/presentation/dto/index.ts +5 -5
- package/src/presentation/dto/mint-registration-tokens.ts +8 -15
- package/src/presentation/dto/poll-demand.ts +3 -1
- package/src/presentation/dto/provisioner-token.ts +5 -0
- package/src/presentation/dto/{provisioned-runners.ts → runner-instances.ts} +13 -15
- package/src/presentation/index.ts +2 -1
- package/src/presentation/inter-module.test.ts +15 -0
- package/src/presentation/inter-module.ts +53 -0
- package/src/presentation/routes/assign-capacity.ts +48 -0
- package/src/presentation/routes/get-provisioner-me.ts +3 -4
- package/src/presentation/routes/heartbeat.test.ts +4 -3
- package/src/presentation/routes/heartbeat.ts +67 -64
- package/src/presentation/routes/index.ts +93 -43
- package/src/presentation/routes/list-active-runners.test.ts +23 -23
- package/src/presentation/routes/manual-registration-tokens.test.ts +4 -3
- package/src/presentation/routes/mint-registration-tokens.test.ts +12 -12
- package/src/presentation/routes/mint-registration-tokens.ts +5 -7
- package/src/presentation/routes/planned-capacity.ts +49 -0
- package/src/presentation/routes/poll-demand-release.test.ts +4 -4
- package/src/presentation/routes/poll-demand.test.ts +161 -22
- package/src/presentation/routes/poll-demand.ts +105 -45
- package/src/presentation/routes/provisioner-me.test.ts +37 -3
- package/src/presentation/routes/{reconcile-provisioned-runners.test.ts → reconcile-runner-instances.test.ts} +66 -61
- package/src/presentation/routes/reconcile-runner-instances.ts +30 -0
- package/src/presentation/routes/register.test.ts +9 -5
- package/src/presentation/routes/register.ts +61 -57
- package/src/presentation/routes/{report-provisioned-runners.test.ts → report-runner-instances.test.ts} +28 -28
- package/src/presentation/routes/{report-provisioned-runners.ts → report-runner-instances.ts} +14 -14
- package/src/presentation/routes/request-job.test.ts +5 -3
- package/src/presentation/routes/request-job.ts +41 -37
- package/src/presentation/routes/runner-enrollment.test.ts +259 -0
- package/src/presentation/routes/runner-enrollment.ts +174 -0
- package/src/temporal/activities/index.ts +2 -2
- package/src/temporal/activities/maintenance-activities.test.ts +7 -7
- package/src/temporal/activities/maintenance-activities.ts +3 -3
- package/src/temporal/workflows/stuck-job-detector.test.ts +3 -3
- package/src/temporal/workflows/stuck-job-detector.ts +2 -2
- package/test/env.ts +1 -3
- package/test/factories/ephemeral-registration-token.ts +2 -2
- package/test/factories/provisioner-token.ts +3 -1
- package/test/factories/runner-instance.ts +57 -0
- package/test/factories/runner-session.ts +3 -1
- package/test/fixtures/auth-inter-module.ts +30 -0
- package/test/globalSetup.ts +5 -1
- package/test/index.ts +2 -1
- package/tsconfig.build.tsbuildinfo +1 -1
- package/dist/core/entities/provisioned-runner.d.ts.map +0 -1
- package/dist/core/entities/provisioned-runner.js +0 -3
- package/dist/core/entities/provisioned-runner.js.map +0 -1
- package/dist/core/provisioned-runners.d.ts +0 -67
- package/dist/core/provisioned-runners.d.ts.map +0 -1
- package/dist/core/provisioned-runners.js +0 -162
- package/dist/core/provisioned-runners.js.map +0 -1
- package/dist/db/provisioned-runners.d.ts +0 -79
- package/dist/db/provisioned-runners.d.ts.map +0 -1
- package/dist/db/provisioned-runners.js +0 -466
- package/dist/db/provisioned-runners.js.map +0 -1
- package/dist/db/schema/provisioned-runners.d.ts.map +0 -1
- package/dist/db/schema/provisioned-runners.js.map +0 -1
- package/dist/presentation/dto/provisioned-runners.d.ts.map +0 -1
- package/dist/presentation/dto/provisioned-runners.js.map +0 -1
- package/dist/presentation/routes/reconcile-provisioned-runners.d.ts +0 -2
- package/dist/presentation/routes/reconcile-provisioned-runners.d.ts.map +0 -1
- package/dist/presentation/routes/reconcile-provisioned-runners.js +0 -27
- package/dist/presentation/routes/reconcile-provisioned-runners.js.map +0 -1
- package/dist/presentation/routes/report-provisioned-runners.d.ts +0 -2
- package/dist/presentation/routes/report-provisioned-runners.d.ts.map +0 -1
- package/dist/presentation/routes/report-provisioned-runners.js +0 -37
- package/dist/presentation/routes/report-provisioned-runners.js.map +0 -1
- package/src/core/provisioned-runners.ts +0 -301
- package/src/db/provisioned-runners.ts +0 -886
- package/src/presentation/routes/reconcile-provisioned-runners.ts +0 -30
- package/test/factories/provisioned-runner.ts +0 -78
package/dist/db/reservations.js
CHANGED
|
@@ -2,6 +2,8 @@ import { canonicalizeLabels } from '@shipfox/runner-labels';
|
|
|
2
2
|
import { and, asc, eq, gt, inArray, lt, sql } from 'drizzle-orm';
|
|
3
3
|
import { db } from './db.js';
|
|
4
4
|
import { pendingJobExecutions } from './schema/pending-job-executions.js';
|
|
5
|
+
import { provisionerCapabilitySnapshots } from './schema/provisioner-capability-snapshots.js';
|
|
6
|
+
import { provisionerTokens } from './schema/provisioner-tokens.js';
|
|
5
7
|
import { reservations } from './schema/reservations.js';
|
|
6
8
|
export async function pollDemandAndReserve(params) {
|
|
7
9
|
return await db().transaction(async (tx)=>{
|
|
@@ -10,7 +12,58 @@ export async function pollDemandAndReserve(params) {
|
|
|
10
12
|
}
|
|
11
13
|
export async function pollDemandAndReserveTx(tx, params) {
|
|
12
14
|
await tx.execute(sql`select pg_advisory_xact_lock(hashtext(${params.workspaceId}))`);
|
|
13
|
-
|
|
15
|
+
return await pollDemandAndReserveLockedTx(tx, params);
|
|
16
|
+
}
|
|
17
|
+
export async function pollInstallationDemandAndReserve(params) {
|
|
18
|
+
const candidateWorkspaceIds = await listInstallationDemandWorkspaceIds(params.eligibleWorkspaceIds);
|
|
19
|
+
const results = [];
|
|
20
|
+
let remainingMaxReservations = params.maxReservations;
|
|
21
|
+
const remainingTemplates = params.templates.map((template)=>({
|
|
22
|
+
...template,
|
|
23
|
+
labels: [
|
|
24
|
+
...canonicalizeLabels(template.labels)
|
|
25
|
+
],
|
|
26
|
+
remainingSlots: template.availableSlots
|
|
27
|
+
}));
|
|
28
|
+
for (const workspaceId of candidateWorkspaceIds){
|
|
29
|
+
if (params.signal?.aborted || remainingMaxReservations === 0) break;
|
|
30
|
+
const result = await db().transaction(async (tx)=>{
|
|
31
|
+
const lockResult = await tx.execute(sql`select pg_try_advisory_xact_lock(hashtext(${workspaceId})) as locked`);
|
|
32
|
+
const locked = lockResult.rows[0];
|
|
33
|
+
if (!locked?.locked) return {
|
|
34
|
+
stats: [],
|
|
35
|
+
reservations: []
|
|
36
|
+
};
|
|
37
|
+
return await pollDemandAndReserveLockedTx(tx, {
|
|
38
|
+
workspaceId,
|
|
39
|
+
provisionerId: params.provisionerId,
|
|
40
|
+
maxReservations: remainingMaxReservations,
|
|
41
|
+
ttlSeconds: params.ttlSeconds,
|
|
42
|
+
templates: remainingTemplates.map((template)=>({
|
|
43
|
+
...template,
|
|
44
|
+
availableSlots: template.remainingSlots
|
|
45
|
+
})),
|
|
46
|
+
capabilityWindowSeconds: params.capabilityWindowSeconds
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
results.push(result);
|
|
50
|
+
consumeInstallationTemplateSlots(remainingTemplates, result.reservations);
|
|
51
|
+
params.onReservations?.(result.reservations);
|
|
52
|
+
remainingMaxReservations -= result.reservations.reduce((total, reservation)=>total + reservation.count, 0);
|
|
53
|
+
}
|
|
54
|
+
return {
|
|
55
|
+
stats: results.flatMap((result)=>result.stats),
|
|
56
|
+
reservations: results.flatMap((result)=>result.reservations)
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
function consumeInstallationTemplateSlots(templates, reservations) {
|
|
60
|
+
for (const reservation of reservations){
|
|
61
|
+
const satisfyingTemplates = templates.filter((template)=>isSubset(reservation.labels, template.labels)).sort((a, b)=>a.labels.length - b.labels.length || a.templateKey.localeCompare(b.templateKey));
|
|
62
|
+
drawSlots(satisfyingTemplates, reservation.count);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
async function pollDemandAndReserveLockedTx(tx, params) {
|
|
66
|
+
let demandRows = (await tx.select({
|
|
14
67
|
requiredLabels: pendingJobExecutions.requiredLabels,
|
|
15
68
|
queued: sql`count(*)::int`,
|
|
16
69
|
oldestQueuedAt: sql`min(${pendingJobExecutions.createdAt})`
|
|
@@ -18,6 +71,13 @@ export async function pollDemandAndReserveTx(tx, params) {
|
|
|
18
71
|
...row,
|
|
19
72
|
oldestQueuedAt: new Date(row.oldestQueuedAt)
|
|
20
73
|
}));
|
|
74
|
+
if (params.capabilityWindowSeconds !== undefined) {
|
|
75
|
+
const capabilityLabels = await listActiveWorkspaceCapabilityLabelsTx(tx, {
|
|
76
|
+
workspaceId: params.workspaceId,
|
|
77
|
+
windowSeconds: params.capabilityWindowSeconds
|
|
78
|
+
});
|
|
79
|
+
demandRows = demandRows.filter((demand)=>!capabilityLabels.some((labels)=>isSubset(demand.requiredLabels, labels)));
|
|
80
|
+
}
|
|
21
81
|
const activeReservationRows = await tx.select({
|
|
22
82
|
requiredLabels: reservations.requiredLabels,
|
|
23
83
|
reserved: sql`coalesce(sum(${reservations.count}), 0)::int`
|
|
@@ -41,6 +101,9 @@ export async function pollDemandAndReserveTx(tx, params) {
|
|
|
41
101
|
const stats = [];
|
|
42
102
|
const grants = [];
|
|
43
103
|
let remainingMaxReservations = params.maxReservations;
|
|
104
|
+
const workspaceIdField = params.capabilityWindowSeconds === undefined ? {} : {
|
|
105
|
+
workspaceId: params.workspaceId
|
|
106
|
+
};
|
|
44
107
|
for (const demand of sortDemandRows(demandRows)){
|
|
45
108
|
const satisfyingTemplates = templates.filter((template)=>isSubset(demand.requiredLabels, template.labels)).sort((a, b)=>a.labels.length - b.labels.length || a.templateKey.localeCompare(b.templateKey));
|
|
46
109
|
if (satisfyingTemplates.length === 0) continue;
|
|
@@ -66,12 +129,14 @@ export async function pollDemandAndReserveTx(tx, params) {
|
|
|
66
129
|
reservedAfterGrant += grant;
|
|
67
130
|
grants.push({
|
|
68
131
|
reservationId: inserted.id,
|
|
132
|
+
...workspaceIdField,
|
|
69
133
|
labels: demand.requiredLabels,
|
|
70
134
|
count: grant,
|
|
71
135
|
expiresAt: inserted.expiresAt
|
|
72
136
|
});
|
|
73
137
|
}
|
|
74
138
|
stats.push({
|
|
139
|
+
...workspaceIdField,
|
|
75
140
|
labels: demand.requiredLabels,
|
|
76
141
|
queued: demand.queued,
|
|
77
142
|
reserved: reservedAfterGrant,
|
|
@@ -83,6 +148,28 @@ export async function pollDemandAndReserveTx(tx, params) {
|
|
|
83
148
|
reservations: grants
|
|
84
149
|
};
|
|
85
150
|
}
|
|
151
|
+
async function listInstallationDemandWorkspaceIds(eligibleWorkspaceIds) {
|
|
152
|
+
if (eligibleWorkspaceIds.size === 0) return [];
|
|
153
|
+
const rows = await db().select({
|
|
154
|
+
workspaceId: pendingJobExecutions.workspaceId,
|
|
155
|
+
oldestQueuedAt: sql`min(${pendingJobExecutions.createdAt})`
|
|
156
|
+
}).from(pendingJobExecutions).where(inArray(pendingJobExecutions.workspaceId, [
|
|
157
|
+
...eligibleWorkspaceIds
|
|
158
|
+
])).groupBy(pendingJobExecutions.workspaceId).orderBy(asc(sql`min(${pendingJobExecutions.createdAt})`), asc(pendingJobExecutions.workspaceId));
|
|
159
|
+
return rows.map((row)=>row.workspaceId);
|
|
160
|
+
}
|
|
161
|
+
export async function listQueuedDemandWorkspaceIds() {
|
|
162
|
+
const rows = await db().select({
|
|
163
|
+
workspaceId: pendingJobExecutions.workspaceId
|
|
164
|
+
}).from(pendingJobExecutions).groupBy(pendingJobExecutions.workspaceId);
|
|
165
|
+
return rows.map((row)=>row.workspaceId);
|
|
166
|
+
}
|
|
167
|
+
async function listActiveWorkspaceCapabilityLabelsTx(tx, params) {
|
|
168
|
+
const rows = await tx.select({
|
|
169
|
+
labels: provisionerCapabilitySnapshots.labels
|
|
170
|
+
}).from(provisionerCapabilitySnapshots).innerJoin(provisionerTokens, eq(provisionerTokens.id, provisionerCapabilitySnapshots.provisionerId)).where(and(eq(provisionerCapabilitySnapshots.workspaceId, params.workspaceId), eq(provisionerTokens.workspaceId, params.workspaceId), eq(provisionerTokens.scope, 'workspace'), sql`${provisionerCapabilitySnapshots.advertisedAt} > now() - (${params.windowSeconds} || ' seconds')::interval`, sql`${provisionerTokens.revokedAt} is null`, sql`(${provisionerTokens.expiresAt} is null or ${provisionerTokens.expiresAt} > now())`));
|
|
171
|
+
return rows.map((row)=>row.labels);
|
|
172
|
+
}
|
|
86
173
|
export async function deleteExpiredReservations(params) {
|
|
87
174
|
const expiredIds = db().select({
|
|
88
175
|
id: reservations.id
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/db/reservations.ts"],"sourcesContent":["import {canonicalizeLabels} from '@shipfox/runner-labels';\nimport {and, asc, eq, gt, inArray, lt, sql} from 'drizzle-orm';\nimport type {Tx} from './db.js';\nimport {db} from './db.js';\nimport {pendingJobExecutions} from './schema/pending-job-executions.js';\nimport {reservations} from './schema/reservations.js';\n\nexport interface ReservationTemplate {\n templateKey: string;\n labels: string[];\n availableSlots: number;\n starting: number;\n running: number;\n}\n\nexport interface DemandStat {\n labels: string[];\n queued: number;\n reserved: number;\n oldestQueuedAt: Date;\n}\n\nexport interface ReservationGrant {\n reservationId: string;\n labels: string[];\n count: number;\n expiresAt: Date;\n}\n\nexport interface PollDemandAndReserveParams {\n workspaceId: string;\n provisionerId: string;\n maxReservations: number;\n ttlSeconds: number;\n templates: ReservationTemplate[];\n}\n\ninterface NormalizedTemplate {\n templateKey: string;\n labels: string[];\n remainingSlots: number;\n}\n\ninterface DemandRow {\n requiredLabels: string[];\n queued: number;\n oldestQueuedAt: Date;\n}\n\nexport async function pollDemandAndReserve(\n params: PollDemandAndReserveParams,\n): Promise<{stats: DemandStat[]; reservations: ReservationGrant[]}> {\n return await db().transaction(async (tx) => {\n return await pollDemandAndReserveTx(tx, params);\n });\n}\n\nexport async function pollDemandAndReserveTx(\n tx: Tx,\n params: PollDemandAndReserveParams,\n): Promise<{stats: DemandStat[]; reservations: ReservationGrant[]}> {\n await tx.execute(sql`select pg_advisory_xact_lock(hashtext(${params.workspaceId}))`);\n\n const demandRows = (\n await tx\n .select({\n requiredLabels: pendingJobExecutions.requiredLabels,\n queued: sql<number>`count(*)::int`,\n oldestQueuedAt: sql<Date | string>`min(${pendingJobExecutions.createdAt})`,\n })\n .from(pendingJobExecutions)\n .where(eq(pendingJobExecutions.workspaceId, params.workspaceId))\n .groupBy(pendingJobExecutions.requiredLabels)\n ).map((row) => ({\n ...row,\n oldestQueuedAt: new Date(row.oldestQueuedAt),\n }));\n\n const activeReservationRows = await tx\n .select({\n requiredLabels: reservations.requiredLabels,\n reserved: sql<number>`coalesce(sum(${reservations.count}), 0)::int`,\n })\n .from(reservations)\n .where(\n and(eq(reservations.workspaceId, params.workspaceId), gt(reservations.expiresAt, sql`now()`)),\n )\n .groupBy(reservations.requiredLabels);\n\n const reservedByLabels = new Map(\n activeReservationRows.map((row) => [labelKey(row.requiredLabels), row.reserved]),\n );\n const activeProvisionerReservationRows = await tx\n .select({\n requiredLabels: reservations.requiredLabels,\n reserved: sql<number>`coalesce(sum(${reservations.count}), 0)::int`,\n })\n .from(reservations)\n .where(\n and(\n eq(reservations.workspaceId, params.workspaceId),\n eq(reservations.provisionerId, params.provisionerId),\n gt(reservations.expiresAt, sql`now()`),\n ),\n )\n .groupBy(reservations.requiredLabels);\n\n const templates = params.templates.map((template) => ({\n templateKey: template.templateKey,\n labels: [...canonicalizeLabels(template.labels)],\n remainingSlots: template.availableSlots,\n }));\n deductProvisionerReservations(templates, activeProvisionerReservationRows);\n const stats: DemandStat[] = [];\n const grants: ReservationGrant[] = [];\n let remainingMaxReservations = params.maxReservations;\n\n for (const demand of sortDemandRows(demandRows)) {\n const satisfyingTemplates = templates\n .filter((template) => isSubset(demand.requiredLabels, template.labels))\n .sort(\n (a, b) => a.labels.length - b.labels.length || a.templateKey.localeCompare(b.templateKey),\n );\n\n if (satisfyingTemplates.length === 0) continue;\n\n const reserved = reservedByLabels.get(labelKey(demand.requiredLabels)) ?? 0;\n const unreserved = Math.max(0, demand.queued - reserved);\n const capacity = satisfyingTemplates.reduce(\n (total, template) => total + template.remainingSlots,\n 0,\n );\n const grant = Math.min(unreserved, capacity, remainingMaxReservations);\n let reservedAfterGrant = reserved;\n\n if (grant > 0 && params.maxReservations > 0) {\n const [inserted] = await tx\n .insert(reservations)\n .values({\n workspaceId: params.workspaceId,\n provisionerId: params.provisionerId,\n requiredLabels: demand.requiredLabels,\n count: grant,\n expiresAt: sql`now() + (${params.ttlSeconds} || ' seconds')::interval`,\n })\n .returning({id: reservations.id, expiresAt: reservations.expiresAt});\n\n if (!inserted) throw new Error('Insert returned no rows');\n\n remainingMaxReservations -= grant;\n drawSlots(satisfyingTemplates, grant);\n reservedAfterGrant += grant;\n grants.push({\n reservationId: inserted.id,\n labels: demand.requiredLabels,\n count: grant,\n expiresAt: inserted.expiresAt,\n });\n }\n\n stats.push({\n labels: demand.requiredLabels,\n queued: demand.queued,\n reserved: reservedAfterGrant,\n oldestQueuedAt: demand.oldestQueuedAt,\n });\n }\n\n return {stats, reservations: grants};\n}\n\nexport async function deleteExpiredReservations(params?: {limit?: number}): Promise<number> {\n const expiredIds = db()\n .select({id: reservations.id})\n .from(reservations)\n .where(lt(reservations.expiresAt, sql`now()`))\n .orderBy(asc(reservations.expiresAt))\n .limit(params?.limit ?? 1000);\n\n const deleted = await db()\n .delete(reservations)\n .where(inArray(reservations.id, expiredIds))\n .returning({id: reservations.id});\n\n return deleted.length;\n}\n\nexport async function deleteReservationsByIds(ids: string[]): Promise<number> {\n if (ids.length === 0) return 0;\n\n const deleted = await db()\n .delete(reservations)\n .where(inArray(reservations.id, ids))\n .returning({id: reservations.id});\n\n return deleted.length;\n}\n\nexport async function releaseReservationUnits(\n tx: Tx,\n params: {\n workspaceId: string;\n provisionerId: string;\n releases: Array<{reservationId: string; count: number}>;\n },\n): Promise<number> {\n let released = 0;\n\n for (const release of params.releases) {\n if (release.count <= 0) continue;\n\n const decremented = await tx\n .update(reservations)\n .set({count: sql`${reservations.count} - ${release.count}`})\n .where(\n and(\n eq(reservations.id, release.reservationId),\n eq(reservations.workspaceId, params.workspaceId),\n eq(reservations.provisionerId, params.provisionerId),\n gt(reservations.count, release.count),\n gt(reservations.expiresAt, sql`now()`),\n ),\n )\n .returning({id: reservations.id});\n\n if (decremented.length > 0) {\n released += release.count;\n continue;\n }\n\n const deleted = await tx\n .delete(reservations)\n .where(\n and(\n eq(reservations.id, release.reservationId),\n eq(reservations.workspaceId, params.workspaceId),\n eq(reservations.provisionerId, params.provisionerId),\n sql`${reservations.count} <= ${release.count}`,\n gt(reservations.expiresAt, sql`now()`),\n ),\n )\n .returning({count: reservations.count});\n\n released += deleted.reduce((total, row) => total + row.count, 0);\n }\n\n return released;\n}\n\nfunction deductProvisionerReservations(\n templates: NormalizedTemplate[],\n activeReservations: {requiredLabels: string[]; reserved: number}[],\n): void {\n for (const reservation of sortReservationRows(activeReservations)) {\n const satisfyingTemplates = templates\n .filter((template) => isSubset(reservation.requiredLabels, template.labels))\n .sort(\n (a, b) => a.labels.length - b.labels.length || a.templateKey.localeCompare(b.templateKey),\n );\n drawSlots(satisfyingTemplates, reservation.reserved);\n }\n}\n\nfunction sortDemandRows(rows: DemandRow[]): DemandRow[] {\n return [...rows].sort((a, b) => {\n const specificity = b.requiredLabels.length - a.requiredLabels.length;\n if (specificity !== 0) return specificity;\n return a.oldestQueuedAt.getTime() - b.oldestQueuedAt.getTime();\n });\n}\n\nfunction sortReservationRows<T extends {requiredLabels: string[]}>(rows: T[]): T[] {\n return [...rows].sort((a, b) => {\n const specificity = b.requiredLabels.length - a.requiredLabels.length;\n if (specificity !== 0) return specificity;\n return labelKey(a.requiredLabels).localeCompare(labelKey(b.requiredLabels));\n });\n}\n\nfunction isSubset(requiredLabels: string[], availableLabels: string[]): boolean {\n return requiredLabels.every((label) => availableLabels.includes(label));\n}\n\nfunction drawSlots(templates: NormalizedTemplate[], count: number): void {\n let remaining = count;\n for (const template of templates) {\n if (remaining === 0) return;\n const used = Math.min(template.remainingSlots, remaining);\n template.remainingSlots -= used;\n remaining -= used;\n }\n}\n\nfunction labelKey(labels: string[]): string {\n return JSON.stringify(labels);\n}\n"],"names":["canonicalizeLabels","and","asc","eq","gt","inArray","lt","sql","db","pendingJobExecutions","reservations","pollDemandAndReserve","params","transaction","tx","pollDemandAndReserveTx","execute","workspaceId","demandRows","select","requiredLabels","queued","oldestQueuedAt","createdAt","from","where","groupBy","map","row","Date","activeReservationRows","reserved","count","expiresAt","reservedByLabels","Map","labelKey","activeProvisionerReservationRows","provisionerId","templates","template","templateKey","labels","remainingSlots","availableSlots","deductProvisionerReservations","stats","grants","remainingMaxReservations","maxReservations","demand","sortDemandRows","satisfyingTemplates","filter","isSubset","sort","a","b","length","localeCompare","get","unreserved","Math","max","capacity","reduce","total","grant","min","reservedAfterGrant","inserted","insert","values","ttlSeconds","returning","id","Error","drawSlots","push","reservationId","deleteExpiredReservations","expiredIds","orderBy","limit","deleted","delete","deleteReservationsByIds","ids","releaseReservationUnits","released","release","releases","decremented","update","set","activeReservations","reservation","sortReservationRows","rows","specificity","getTime","availableLabels","every","label","includes","remaining","used","JSON","stringify"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/db/reservations.ts"],"sourcesContent":["import {canonicalizeLabels} from '@shipfox/runner-labels';\nimport {and, asc, eq, gt, inArray, lt, sql} from 'drizzle-orm';\nimport type {Tx} from './db.js';\nimport {db} from './db.js';\nimport {pendingJobExecutions} from './schema/pending-job-executions.js';\nimport {provisionerCapabilitySnapshots} from './schema/provisioner-capability-snapshots.js';\nimport {provisionerTokens} from './schema/provisioner-tokens.js';\nimport {reservations} from './schema/reservations.js';\n\nexport interface ReservationTemplate {\n templateKey: string;\n labels: string[];\n availableSlots: number;\n starting: number;\n running: number;\n}\n\nexport interface DemandStat {\n workspaceId?: string;\n labels: string[];\n queued: number;\n reserved: number;\n oldestQueuedAt: Date;\n}\n\nexport interface ReservationGrant {\n reservationId: string;\n workspaceId?: string;\n labels: string[];\n count: number;\n expiresAt: Date;\n}\n\nexport interface PollDemandAndReserveParams {\n workspaceId: string;\n provisionerId: string;\n maxReservations: number;\n ttlSeconds: number;\n templates: ReservationTemplate[];\n capabilityWindowSeconds?: number;\n}\n\nexport interface InstallationPollDemandAndReserveParams {\n provisionerId: string;\n maxReservations: number;\n ttlSeconds: number;\n templates: ReservationTemplate[];\n capabilityWindowSeconds: number;\n eligibleWorkspaceIds: ReadonlySet<string>;\n signal?: AbortSignal;\n onReservations?: (reservations: ReservationGrant[]) => void;\n}\n\ninterface NormalizedTemplate {\n templateKey: string;\n labels: string[];\n remainingSlots: number;\n}\n\ninterface DemandRow {\n requiredLabels: string[];\n queued: number;\n oldestQueuedAt: Date;\n}\n\nexport async function pollDemandAndReserve(\n params: PollDemandAndReserveParams,\n): Promise<{stats: DemandStat[]; reservations: ReservationGrant[]}> {\n return await db().transaction(async (tx) => {\n return await pollDemandAndReserveTx(tx, params);\n });\n}\n\nexport async function pollDemandAndReserveTx(\n tx: Tx,\n params: PollDemandAndReserveParams,\n): Promise<{stats: DemandStat[]; reservations: ReservationGrant[]}> {\n await tx.execute(sql`select pg_advisory_xact_lock(hashtext(${params.workspaceId}))`);\n return await pollDemandAndReserveLockedTx(tx, params);\n}\n\nexport async function pollInstallationDemandAndReserve(\n params: InstallationPollDemandAndReserveParams,\n): Promise<{stats: DemandStat[]; reservations: ReservationGrant[]}> {\n const candidateWorkspaceIds = await listInstallationDemandWorkspaceIds(\n params.eligibleWorkspaceIds,\n );\n const results: Array<{stats: DemandStat[]; reservations: ReservationGrant[]}> = [];\n let remainingMaxReservations = params.maxReservations;\n const remainingTemplates = params.templates.map((template) => ({\n ...template,\n labels: [...canonicalizeLabels(template.labels)],\n remainingSlots: template.availableSlots,\n }));\n for (const workspaceId of candidateWorkspaceIds) {\n if (params.signal?.aborted || remainingMaxReservations === 0) break;\n const result = await db().transaction(async (tx) => {\n const lockResult = await tx.execute<{locked: boolean}>(\n sql`select pg_try_advisory_xact_lock(hashtext(${workspaceId})) as locked`,\n );\n const locked = lockResult.rows[0];\n if (!locked?.locked) return {stats: [], reservations: []};\n return await pollDemandAndReserveLockedTx(tx, {\n workspaceId,\n provisionerId: params.provisionerId,\n maxReservations: remainingMaxReservations,\n ttlSeconds: params.ttlSeconds,\n templates: remainingTemplates.map((template) => ({\n ...template,\n availableSlots: template.remainingSlots,\n })),\n capabilityWindowSeconds: params.capabilityWindowSeconds,\n });\n });\n results.push(result);\n consumeInstallationTemplateSlots(remainingTemplates, result.reservations);\n params.onReservations?.(result.reservations);\n remainingMaxReservations -= result.reservations.reduce(\n (total, reservation) => total + reservation.count,\n 0,\n );\n }\n return {\n stats: results.flatMap((result) => result.stats),\n reservations: results.flatMap((result) => result.reservations),\n };\n}\n\nfunction consumeInstallationTemplateSlots(\n templates: NormalizedTemplate[],\n reservations: ReservationGrant[],\n): void {\n for (const reservation of reservations) {\n const satisfyingTemplates = templates\n .filter((template) => isSubset(reservation.labels, template.labels))\n .sort(\n (a, b) => a.labels.length - b.labels.length || a.templateKey.localeCompare(b.templateKey),\n );\n drawSlots(satisfyingTemplates, reservation.count);\n }\n}\n\nasync function pollDemandAndReserveLockedTx(\n tx: Tx,\n params: PollDemandAndReserveParams,\n): Promise<{stats: DemandStat[]; reservations: ReservationGrant[]}> {\n let demandRows = (\n await tx\n .select({\n requiredLabels: pendingJobExecutions.requiredLabels,\n queued: sql<number>`count(*)::int`,\n oldestQueuedAt: sql<Date | string>`min(${pendingJobExecutions.createdAt})`,\n })\n .from(pendingJobExecutions)\n .where(eq(pendingJobExecutions.workspaceId, params.workspaceId))\n .groupBy(pendingJobExecutions.requiredLabels)\n ).map((row) => ({\n ...row,\n oldestQueuedAt: new Date(row.oldestQueuedAt),\n }));\n if (params.capabilityWindowSeconds !== undefined) {\n const capabilityLabels = await listActiveWorkspaceCapabilityLabelsTx(tx, {\n workspaceId: params.workspaceId,\n windowSeconds: params.capabilityWindowSeconds,\n });\n demandRows = demandRows.filter(\n (demand) => !capabilityLabels.some((labels) => isSubset(demand.requiredLabels, labels)),\n );\n }\n\n const activeReservationRows = await tx\n .select({\n requiredLabels: reservations.requiredLabels,\n reserved: sql<number>`coalesce(sum(${reservations.count}), 0)::int`,\n })\n .from(reservations)\n .where(\n and(eq(reservations.workspaceId, params.workspaceId), gt(reservations.expiresAt, sql`now()`)),\n )\n .groupBy(reservations.requiredLabels);\n\n const reservedByLabels = new Map(\n activeReservationRows.map((row) => [labelKey(row.requiredLabels), row.reserved]),\n );\n const activeProvisionerReservationRows = await tx\n .select({\n requiredLabels: reservations.requiredLabels,\n reserved: sql<number>`coalesce(sum(${reservations.count}), 0)::int`,\n })\n .from(reservations)\n .where(\n and(\n eq(reservations.workspaceId, params.workspaceId),\n eq(reservations.provisionerId, params.provisionerId),\n gt(reservations.expiresAt, sql`now()`),\n ),\n )\n .groupBy(reservations.requiredLabels);\n\n const templates = params.templates.map((template) => ({\n templateKey: template.templateKey,\n labels: [...canonicalizeLabels(template.labels)],\n remainingSlots: template.availableSlots,\n }));\n deductProvisionerReservations(templates, activeProvisionerReservationRows);\n const stats: DemandStat[] = [];\n const grants: ReservationGrant[] = [];\n let remainingMaxReservations = params.maxReservations;\n const workspaceIdField =\n params.capabilityWindowSeconds === undefined ? {} : {workspaceId: params.workspaceId};\n\n for (const demand of sortDemandRows(demandRows)) {\n const satisfyingTemplates = templates\n .filter((template) => isSubset(demand.requiredLabels, template.labels))\n .sort(\n (a, b) => a.labels.length - b.labels.length || a.templateKey.localeCompare(b.templateKey),\n );\n\n if (satisfyingTemplates.length === 0) continue;\n\n const reserved = reservedByLabels.get(labelKey(demand.requiredLabels)) ?? 0;\n const unreserved = Math.max(0, demand.queued - reserved);\n const capacity = satisfyingTemplates.reduce(\n (total, template) => total + template.remainingSlots,\n 0,\n );\n const grant = Math.min(unreserved, capacity, remainingMaxReservations);\n let reservedAfterGrant = reserved;\n\n if (grant > 0 && params.maxReservations > 0) {\n const [inserted] = await tx\n .insert(reservations)\n .values({\n workspaceId: params.workspaceId,\n provisionerId: params.provisionerId,\n requiredLabels: demand.requiredLabels,\n count: grant,\n expiresAt: sql`now() + (${params.ttlSeconds} || ' seconds')::interval`,\n })\n .returning({id: reservations.id, expiresAt: reservations.expiresAt});\n\n if (!inserted) throw new Error('Insert returned no rows');\n\n remainingMaxReservations -= grant;\n drawSlots(satisfyingTemplates, grant);\n reservedAfterGrant += grant;\n grants.push({\n reservationId: inserted.id,\n ...workspaceIdField,\n labels: demand.requiredLabels,\n count: grant,\n expiresAt: inserted.expiresAt,\n });\n }\n\n stats.push({\n ...workspaceIdField,\n labels: demand.requiredLabels,\n queued: demand.queued,\n reserved: reservedAfterGrant,\n oldestQueuedAt: demand.oldestQueuedAt,\n });\n }\n\n return {stats, reservations: grants};\n}\n\nasync function listInstallationDemandWorkspaceIds(eligibleWorkspaceIds: ReadonlySet<string>) {\n if (eligibleWorkspaceIds.size === 0) return [];\n const rows = await db()\n .select({\n workspaceId: pendingJobExecutions.workspaceId,\n oldestQueuedAt: sql<Date>`min(${pendingJobExecutions.createdAt})`,\n })\n .from(pendingJobExecutions)\n .where(inArray(pendingJobExecutions.workspaceId, [...eligibleWorkspaceIds]))\n .groupBy(pendingJobExecutions.workspaceId)\n .orderBy(\n asc(sql`min(${pendingJobExecutions.createdAt})`),\n asc(pendingJobExecutions.workspaceId),\n );\n return rows.map((row) => row.workspaceId);\n}\n\nexport async function listQueuedDemandWorkspaceIds(): Promise<string[]> {\n const rows = await db()\n .select({workspaceId: pendingJobExecutions.workspaceId})\n .from(pendingJobExecutions)\n .groupBy(pendingJobExecutions.workspaceId);\n return rows.map((row) => row.workspaceId);\n}\n\nasync function listActiveWorkspaceCapabilityLabelsTx(\n tx: Tx,\n params: {workspaceId: string; windowSeconds: number},\n): Promise<string[][]> {\n const rows = await tx\n .select({labels: provisionerCapabilitySnapshots.labels})\n .from(provisionerCapabilitySnapshots)\n .innerJoin(\n provisionerTokens,\n eq(provisionerTokens.id, provisionerCapabilitySnapshots.provisionerId),\n )\n .where(\n and(\n eq(provisionerCapabilitySnapshots.workspaceId, params.workspaceId),\n eq(provisionerTokens.workspaceId, params.workspaceId),\n eq(provisionerTokens.scope, 'workspace'),\n sql`${provisionerCapabilitySnapshots.advertisedAt} > now() - (${params.windowSeconds} || ' seconds')::interval`,\n sql`${provisionerTokens.revokedAt} is null`,\n sql`(${provisionerTokens.expiresAt} is null or ${provisionerTokens.expiresAt} > now())`,\n ),\n );\n return rows.map((row) => row.labels);\n}\n\nexport async function deleteExpiredReservations(params?: {limit?: number}): Promise<number> {\n const expiredIds = db()\n .select({id: reservations.id})\n .from(reservations)\n .where(lt(reservations.expiresAt, sql`now()`))\n .orderBy(asc(reservations.expiresAt))\n .limit(params?.limit ?? 1000);\n\n const deleted = await db()\n .delete(reservations)\n .where(inArray(reservations.id, expiredIds))\n .returning({id: reservations.id});\n\n return deleted.length;\n}\n\nexport async function deleteReservationsByIds(ids: string[]): Promise<number> {\n if (ids.length === 0) return 0;\n\n const deleted = await db()\n .delete(reservations)\n .where(inArray(reservations.id, ids))\n .returning({id: reservations.id});\n\n return deleted.length;\n}\n\nexport async function releaseReservationUnits(\n tx: Tx,\n params: {\n workspaceId: string;\n provisionerId: string;\n releases: Array<{reservationId: string; count: number}>;\n },\n): Promise<number> {\n let released = 0;\n\n for (const release of params.releases) {\n if (release.count <= 0) continue;\n\n const decremented = await tx\n .update(reservations)\n .set({count: sql`${reservations.count} - ${release.count}`})\n .where(\n and(\n eq(reservations.id, release.reservationId),\n eq(reservations.workspaceId, params.workspaceId),\n eq(reservations.provisionerId, params.provisionerId),\n gt(reservations.count, release.count),\n gt(reservations.expiresAt, sql`now()`),\n ),\n )\n .returning({id: reservations.id});\n\n if (decremented.length > 0) {\n released += release.count;\n continue;\n }\n\n const deleted = await tx\n .delete(reservations)\n .where(\n and(\n eq(reservations.id, release.reservationId),\n eq(reservations.workspaceId, params.workspaceId),\n eq(reservations.provisionerId, params.provisionerId),\n sql`${reservations.count} <= ${release.count}`,\n gt(reservations.expiresAt, sql`now()`),\n ),\n )\n .returning({count: reservations.count});\n\n released += deleted.reduce((total, row) => total + row.count, 0);\n }\n\n return released;\n}\n\nfunction deductProvisionerReservations(\n templates: NormalizedTemplate[],\n activeReservations: {requiredLabels: string[]; reserved: number}[],\n): void {\n for (const reservation of sortReservationRows(activeReservations)) {\n const satisfyingTemplates = templates\n .filter((template) => isSubset(reservation.requiredLabels, template.labels))\n .sort(\n (a, b) => a.labels.length - b.labels.length || a.templateKey.localeCompare(b.templateKey),\n );\n drawSlots(satisfyingTemplates, reservation.reserved);\n }\n}\n\nfunction sortDemandRows(rows: DemandRow[]): DemandRow[] {\n return [...rows].sort((a, b) => {\n const specificity = b.requiredLabels.length - a.requiredLabels.length;\n if (specificity !== 0) return specificity;\n return a.oldestQueuedAt.getTime() - b.oldestQueuedAt.getTime();\n });\n}\n\nfunction sortReservationRows<T extends {requiredLabels: string[]}>(rows: T[]): T[] {\n return [...rows].sort((a, b) => {\n const specificity = b.requiredLabels.length - a.requiredLabels.length;\n if (specificity !== 0) return specificity;\n return labelKey(a.requiredLabels).localeCompare(labelKey(b.requiredLabels));\n });\n}\n\nfunction isSubset(requiredLabels: string[], availableLabels: string[]): boolean {\n return requiredLabels.every((label) => availableLabels.includes(label));\n}\n\nfunction drawSlots(templates: NormalizedTemplate[], count: number): void {\n let remaining = count;\n for (const template of templates) {\n if (remaining === 0) return;\n const used = Math.min(template.remainingSlots, remaining);\n template.remainingSlots -= used;\n remaining -= used;\n }\n}\n\nfunction labelKey(labels: string[]): string {\n return JSON.stringify(labels);\n}\n"],"names":["canonicalizeLabels","and","asc","eq","gt","inArray","lt","sql","db","pendingJobExecutions","provisionerCapabilitySnapshots","provisionerTokens","reservations","pollDemandAndReserve","params","transaction","tx","pollDemandAndReserveTx","execute","workspaceId","pollDemandAndReserveLockedTx","pollInstallationDemandAndReserve","candidateWorkspaceIds","listInstallationDemandWorkspaceIds","eligibleWorkspaceIds","results","remainingMaxReservations","maxReservations","remainingTemplates","templates","map","template","labels","remainingSlots","availableSlots","signal","aborted","result","lockResult","locked","rows","stats","provisionerId","ttlSeconds","capabilityWindowSeconds","push","consumeInstallationTemplateSlots","onReservations","reduce","total","reservation","count","flatMap","satisfyingTemplates","filter","isSubset","sort","a","b","length","templateKey","localeCompare","drawSlots","demandRows","select","requiredLabels","queued","oldestQueuedAt","createdAt","from","where","groupBy","row","Date","undefined","capabilityLabels","listActiveWorkspaceCapabilityLabelsTx","windowSeconds","demand","some","activeReservationRows","reserved","expiresAt","reservedByLabels","Map","labelKey","activeProvisionerReservationRows","deductProvisionerReservations","grants","workspaceIdField","sortDemandRows","get","unreserved","Math","max","capacity","grant","min","reservedAfterGrant","inserted","insert","values","returning","id","Error","reservationId","size","orderBy","listQueuedDemandWorkspaceIds","innerJoin","scope","advertisedAt","revokedAt","deleteExpiredReservations","expiredIds","limit","deleted","delete","deleteReservationsByIds","ids","releaseReservationUnits","released","release","releases","decremented","update","set","activeReservations","sortReservationRows","specificity","getTime","availableLabels","every","label","includes","remaining","used","JSON","stringify"],"mappings":"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"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import type { RunnerInstance, RunnerInstanceState } from '#core/entities/runner-instance.js';
|
|
2
|
+
import type { Tx } from './db.js';
|
|
3
|
+
import { type RunnerInstanceBoundJobExecution } from './job-executions.js';
|
|
4
|
+
export declare const terminalStates: readonly ["stopped", "failed", "terminated"];
|
|
5
|
+
export declare const activeStates: readonly ["starting", "running", "stopping"];
|
|
6
|
+
export declare const divergenceCountStates: readonly ["starting", "running"];
|
|
7
|
+
export type RunnerInstanceTerminateIntentReason = 'job-cancelled';
|
|
8
|
+
export interface RunnerInstanceTerminateIntent {
|
|
9
|
+
providerRunnerId: string;
|
|
10
|
+
reason: RunnerInstanceTerminateIntentReason;
|
|
11
|
+
}
|
|
12
|
+
export interface ActiveRunnerInstanceTemplateCount {
|
|
13
|
+
templateKey: string;
|
|
14
|
+
state: (typeof divergenceCountStates)[number];
|
|
15
|
+
count: number;
|
|
16
|
+
}
|
|
17
|
+
export interface RunnerInstanceReportEvent {
|
|
18
|
+
providerRunnerId: string;
|
|
19
|
+
reservationId: string | null;
|
|
20
|
+
templateKey: string | null;
|
|
21
|
+
labels: string[];
|
|
22
|
+
state: RunnerInstanceState;
|
|
23
|
+
reason: string | null;
|
|
24
|
+
runnerSessionId: string | null;
|
|
25
|
+
providerKind: string | null;
|
|
26
|
+
reportedAt: Date;
|
|
27
|
+
}
|
|
28
|
+
export interface ReportRunnerInstancesParams {
|
|
29
|
+
workspaceId: string | null;
|
|
30
|
+
provisionerId: string;
|
|
31
|
+
events: RunnerInstanceReportEvent[];
|
|
32
|
+
}
|
|
33
|
+
export interface ReconcileRunnerInstancesParams {
|
|
34
|
+
workspaceId: string | null;
|
|
35
|
+
provisionerId: string;
|
|
36
|
+
observedRunnerInstanceIds: string[];
|
|
37
|
+
terminateGraceSeconds: number;
|
|
38
|
+
}
|
|
39
|
+
export interface ReconcileRunnerInstancesDbResult {
|
|
40
|
+
observedRows: RunnerInstance[];
|
|
41
|
+
boundJobExecutionsByRunnerInstanceId: Map<string, RunnerInstanceBoundJobExecution>;
|
|
42
|
+
absentIds: string[];
|
|
43
|
+
reservationsReleased: number;
|
|
44
|
+
}
|
|
45
|
+
export interface ReapStaleRunnerInstancesResult {
|
|
46
|
+
reaped: number;
|
|
47
|
+
reservationsReleased: number;
|
|
48
|
+
}
|
|
49
|
+
export declare function createPlannedProvisionedCapacity(params: {
|
|
50
|
+
provisionerId: string;
|
|
51
|
+
providerKind: string | null;
|
|
52
|
+
templateKey: string | null;
|
|
53
|
+
}): Promise<{
|
|
54
|
+
capacityId: string;
|
|
55
|
+
}>;
|
|
56
|
+
export declare function attachProviderRunnerId(params: {
|
|
57
|
+
capacityId: string;
|
|
58
|
+
provisionerId: string;
|
|
59
|
+
providerRunnerId: string;
|
|
60
|
+
}): Promise<boolean>;
|
|
61
|
+
export declare function reportRunnerInstances(params: ReportRunnerInstancesParams): Promise<{
|
|
62
|
+
accepted: number;
|
|
63
|
+
reservationsReleased: number;
|
|
64
|
+
terminateIntentsHonored: RunnerInstanceTerminateIntent[];
|
|
65
|
+
}>;
|
|
66
|
+
export declare function listActiveRunnerInstanceCountsByTemplateTx(tx: Tx, params: {
|
|
67
|
+
workspaceId: string;
|
|
68
|
+
provisionerId: string;
|
|
69
|
+
}): Promise<ActiveRunnerInstanceTemplateCount[]>;
|
|
70
|
+
export declare function listActiveRunnerInstances(params: {
|
|
71
|
+
workspaceId: string;
|
|
72
|
+
windowSeconds: number;
|
|
73
|
+
limit?: number;
|
|
74
|
+
}): Promise<RunnerInstance[]>;
|
|
75
|
+
export declare function listProvisionerTerminateIntents(params: {
|
|
76
|
+
workspaceId: string;
|
|
77
|
+
provisionerId: string;
|
|
78
|
+
limit: number;
|
|
79
|
+
}): Promise<string[]>;
|
|
80
|
+
export declare function listProvisionerTerminateIntentRowsTx(tx: Tx, params: {
|
|
81
|
+
workspaceId: string;
|
|
82
|
+
provisionerId: string;
|
|
83
|
+
limit: number;
|
|
84
|
+
}): Promise<RunnerInstanceTerminateIntent[]>;
|
|
85
|
+
export declare function reconcileRunnerInstances(params: ReconcileRunnerInstancesParams): Promise<ReconcileRunnerInstancesDbResult>;
|
|
86
|
+
export declare function reapStaleRunnerInstances(params: {
|
|
87
|
+
thresholdSeconds: number;
|
|
88
|
+
limit: number;
|
|
89
|
+
}): Promise<ReapStaleRunnerInstancesResult>;
|
|
90
|
+
export declare function isTerminalState(state: RunnerInstanceState): boolean;
|
|
91
|
+
//# sourceMappingURL=runner-instances.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner-instances.d.ts","sourceRoot":"","sources":["../../src/db/runner-instances.ts"],"names":[],"mappings":"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"}
|