@shipfox/api-runners 5.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 +61 -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 +21 -16
- 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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/db/job-executions.ts"],"sourcesContent":["import {\n RUNNER_JOB_CLAIMED,\n RUNNER_JOB_LEASE_EXPIRED,\n RUNNER_JOB_QUEUED,\n type RunnersEventMap,\n type RunnerToolCapabilitiesDto,\n} from '@shipfox/api-runners-dto';\nimport {logger} from '@shipfox/node-opentelemetry';\nimport {writeOutboxEvent, writeOutboxEvents} from '@shipfox/node-outbox';\nimport {canonicalizeLabels} from '@shipfox/runner-labels';\nimport {\n and,\n arrayContained,\n asc,\n count,\n desc,\n eq,\n gt,\n inArray,\n isNotNull,\n isNull,\n lt,\n lte,\n or,\n sql,\n} from 'drizzle-orm';\nimport {\n EmptyRequiredLabelsError,\n RunnerSessionExhaustedError,\n RunningJobExecutionNotFoundError,\n} from '#core/errors.js';\nimport {jobExecutionEnqueuedCount, jobExecutionLeaseExpiredCount} from '#metrics/instance.js';\nimport type {Tx} from './db.js';\nimport {db} from './db.js';\nimport {runnersOutbox} from './schema/outbox.js';\nimport {pendingJobExecutions} from './schema/pending-job-executions.js';\nimport {runnerSessions} from './schema/runner-sessions.js';\nimport {runningJobExecutions} from './schema/running-job-executions.js';\n\nexport interface EnqueueJobExecutionParams {\n workspaceId: string;\n workflowRunId: string;\n workflowRunAttemptId: string;\n jobId: string;\n jobExecutionId: string;\n projectId: string;\n requiredLabels: string[];\n}\n\n// Idempotent while the job execution is still pending: a duplicate jobExecutionId already in\n// `runners_pending_jobs` is a no-op. Temporal retries the enqueue activity\n// at-least-once, so a unique-violation throw on a retry-after-lost-result\n// would permanently fail a healthy job execution's workflow. The guard does not extend\n// past the claim: once the job execution has moved to `runners_running_jobs`, a retry\n// can reinsert an orphan pending row, which a later `claimPendingJobExecution` drops\n// via the running-execution unique constraint (onConflictDoNothing) instead of failing.\nexport async function enqueueJobExecution(params: EnqueueJobExecutionParams): Promise<void> {\n const requiredLabels = [...canonicalizeLabels(params.requiredLabels)];\n if (requiredLabels.length === 0) throw new EmptyRequiredLabelsError();\n\n const enqueued = await db().transaction(async (tx) => {\n const [inserted] = await tx\n .insert(pendingJobExecutions)\n .values({\n workspaceId: params.workspaceId,\n workflowRunId: params.workflowRunId,\n workflowRunAttemptId: params.workflowRunAttemptId,\n jobId: params.jobId,\n jobExecutionId: params.jobExecutionId,\n projectId: params.projectId,\n requiredLabels,\n })\n .onConflictDoNothing({target: pendingJobExecutions.jobExecutionId})\n .returning({createdAt: pendingJobExecutions.createdAt});\n\n // A retry that hits the conflict inserts nothing: the first enqueue already\n // emitted the queued event (durably, in the outbox), so re-emitting would\n // only add a redundant row the subscriber coalesces away. Skip it.\n if (!inserted) return false;\n\n await writeOutboxEvent<RunnersEventMap>(tx, runnersOutbox, {\n type: RUNNER_JOB_QUEUED,\n payload: {\n workflowRunId: params.workflowRunId,\n workflowRunAttemptId: params.workflowRunAttemptId,\n jobId: params.jobId,\n jobExecutionId: params.jobExecutionId,\n queuedAt: inserted.createdAt.toISOString(),\n },\n });\n return true;\n });\n\n if (enqueued) jobExecutionEnqueuedCount.add(1);\n}\n\nexport interface ClaimedJobExecution {\n workflowRunId: string;\n workflowRunAttemptId: string;\n jobId: string;\n jobExecutionId: string;\n projectId: string;\n}\n\nexport interface ActiveRunningJobExecution {\n workflowRunId: string;\n workflowRunAttemptId: string;\n jobId: string;\n jobExecutionId: string;\n projectId: string;\n runnerSessionId: string;\n provisionerId: string | null;\n provisionedRunnerId: string | null;\n requiredLabels: string[];\n runnerLabels: string[];\n startedAt: Date;\n lastHeartbeatAt: Date;\n}\n\nexport interface ProvisionedRunnerBoundJobExecution {\n workflowRunId: string;\n workflowRunAttemptId: string;\n jobId: string;\n jobExecutionId: string;\n provisionedRunnerId: string;\n startedAt: Date;\n lastHeartbeatAt: Date;\n cancellationRequestedAt: Date | null;\n}\n\nexport async function claimPendingJobExecution(params: {\n workspaceId: string;\n runnerSessionId: string;\n sessionLabels: string[];\n maxClaims: number | null;\n runnerSessionLivenessThrottleSeconds: number;\n}): Promise<ClaimedJobExecution | null> {\n await touchRunnerSessionLiveness({\n workspaceId: params.workspaceId,\n runnerSessionId: params.runnerSessionId,\n throttleSeconds: params.runnerSessionLivenessThrottleSeconds,\n });\n\n if (params.sessionLabels.length === 0) return null;\n\n return await db().transaction(async (tx) => {\n let provisionerId: string | null = null;\n let provisionedRunnerId: string | null = null;\n\n if (params.maxClaims !== null) {\n const [session] = await tx\n .select({\n maxClaims: runnerSessions.maxClaims,\n claimsUsed: runnerSessions.claimsUsed,\n provisionerId: runnerSessions.provisionerId,\n provisionedRunnerId: runnerSessions.provisionedRunnerId,\n })\n .from(runnerSessions)\n .where(eq(runnerSessions.id, params.runnerSessionId))\n .limit(1)\n .for('update');\n\n if (!session || session.maxClaims === null || session.claimsUsed >= session.maxClaims) {\n throw new RunnerSessionExhaustedError(params.runnerSessionId);\n }\n\n // Ephemeral sessions are the only capped sessions, and the DB check keeps\n // their provisioned-runner link present as a pair.\n provisionerId = session.provisionerId;\n provisionedRunnerId = session.provisionedRunnerId;\n }\n\n // `id` is a uuidv7 (time-ordered), so it is a deterministic FIFO tiebreaker\n // for rows sharing a created_at within a batch.\n const [row] = await tx\n .select()\n .from(pendingJobExecutions)\n .where(\n and(\n eq(pendingJobExecutions.workspaceId, params.workspaceId),\n arrayContained(pendingJobExecutions.requiredLabels, params.sessionLabels),\n ),\n )\n .orderBy(asc(pendingJobExecutions.createdAt), asc(pendingJobExecutions.id))\n .limit(1)\n .for('update', {skipLocked: true});\n\n if (!row) return null;\n\n await tx.delete(pendingJobExecutions).where(eq(pendingJobExecutions.id, row.id));\n\n // An enqueue retry that lands after a prior claim can leave an orphan pending\n // row whose jobExecutionId is already in `runners_running_jobs`. Insert-or-skip\n // on the jobExecutionId unique constraint: when the job execution is already running\n // the insert touches no row, so we commit the orphan's deletion and return\n // null rather than let the unique violation roll the claim back into a poison\n // loop. The runner just re-polls for a real job execution.\n const inserted = await tx\n .insert(runningJobExecutions)\n .values({\n workspaceId: row.workspaceId,\n workflowRunId: row.workflowRunId,\n workflowRunAttemptId: row.workflowRunAttemptId,\n jobId: row.jobId,\n jobExecutionId: row.jobExecutionId,\n projectId: row.projectId,\n runnerSessionId: params.runnerSessionId,\n provisionerId,\n provisionedRunnerId,\n requiredLabels: row.requiredLabels,\n runnerLabels: params.sessionLabels,\n })\n .onConflictDoNothing({target: runningJobExecutions.jobExecutionId})\n .returning({claimedAt: runningJobExecutions.startedAt});\n\n const claimed = inserted[0];\n if (!claimed) return null;\n\n if (params.maxClaims !== null) {\n await tx\n .update(runnerSessions)\n .set({claimsUsed: sql`${runnerSessions.claimsUsed} + 1`, updatedAt: sql`now()`})\n .where(eq(runnerSessions.id, params.runnerSessionId));\n }\n\n // The running-row insert is the runner claiming the job execution. Emit in the same tx; the\n // payload carries the row's own claim instant so a consumer records the true time,\n // not the outbox drain time.\n await writeOutboxEvent<RunnersEventMap>(tx, runnersOutbox, {\n type: RUNNER_JOB_CLAIMED,\n payload: {\n workflowRunId: row.workflowRunId,\n workflowRunAttemptId: row.workflowRunAttemptId,\n jobId: row.jobId,\n jobExecutionId: row.jobExecutionId,\n claimedAt: claimed.claimedAt.toISOString(),\n },\n });\n\n return {\n workflowRunId: row.workflowRunId,\n workflowRunAttemptId: row.workflowRunAttemptId,\n jobId: row.jobId,\n jobExecutionId: row.jobExecutionId,\n projectId: row.projectId,\n };\n });\n}\n\nasync function touchRunnerSessionLiveness(params: {\n workspaceId: string;\n runnerSessionId: string;\n throttleSeconds: number;\n}): Promise<void> {\n await db()\n .update(runnerSessions)\n .set({updatedAt: sql`now()`})\n .where(\n and(\n eq(runnerSessions.id, params.runnerSessionId),\n eq(runnerSessions.workspaceId, params.workspaceId),\n sql`${runnerSessions.updatedAt} < now() - (${params.throttleSeconds} || ' seconds')::interval`,\n ),\n );\n}\n\n/**\n * Releases a job execution's lease when the orchestration workflow finalizes it: deletes the\n * running-job-execution row AND any lingering pending row for the same execution, in one tx.\n * Idempotent (0-row no-op), no token scope (the workflow is authoritative), and\n * emits no event — the workflow already owns the outcome. Sweeping the pending row\n * too closes the at-least-once window where an enqueue retry left an orphan that a\n * later claim would otherwise pick up for an already-finished job execution.\n */\nexport async function releaseJobExecution(params: {jobExecutionId: string}): Promise<void> {\n await db().transaction(async (tx) => {\n // Delete pending before running to match `claimPendingJobExecution`'s lock-acquisition\n // order (it locks the pending row first, then the running row). A concurrent\n // claim picking up an orphan pending row for this same job execution would otherwise\n // deadlock against the reverse order here.\n await tx\n .delete(pendingJobExecutions)\n .where(eq(pendingJobExecutions.jobExecutionId, params.jobExecutionId));\n await tx\n .delete(runningJobExecutions)\n .where(eq(runningJobExecutions.jobExecutionId, params.jobExecutionId));\n });\n}\n\n/**\n * Reaps stale leases (bounded by `limit`), emitting one\n * `runners.job.lease_expired` event per reaped job execution.\n *\n * The cutoff is re-checked in the DELETE, not just the locking subquery, so a\n * heartbeat landing mid-call spares the live row. Each reaped execution also sweeps its\n * pending row: a failed best-effort `releaseJobExecution` would otherwise leave an orphan\n * that a later claim re-runs as an already-finished job execution.\n *\n * Locks running-then-pending, the inverse of `claimPendingJobExecution` / `releaseJobExecution`.\n * That pre-existing asymmetry opens a narrow deadlock window against a concurrent\n * claim of the same orphan-pending job execution; Postgres breaks it and the cron retries.\n */\nexport async function expireStuckJobExecutions(params: {\n thresholdSeconds: number;\n noFirstHeartbeatGraceSeconds: number;\n limit?: number;\n}): Promise<\n Array<{\n workflowRunId: string;\n workflowRunAttemptId: string;\n jobId: string;\n jobExecutionId: string;\n }>\n> {\n const reaped = await db().transaction(async (tx) => {\n const heartbeatCutoff = sql`now() - (${params.thresholdSeconds} || ' seconds')::interval`;\n const firstHeartbeatCutoff = sql`now() - (${params.noFirstHeartbeatGraceSeconds} || ' seconds')::interval`;\n const stalePredicate = or(\n and(\n isNull(runningJobExecutions.firstHeartbeatAt),\n lte(runningJobExecutions.lastHeartbeatAt, runningJobExecutions.startedAt),\n lt(runningJobExecutions.startedAt, firstHeartbeatCutoff),\n ),\n and(\n or(\n isNotNull(runningJobExecutions.firstHeartbeatAt),\n gt(runningJobExecutions.lastHeartbeatAt, runningJobExecutions.startedAt),\n ),\n lt(runningJobExecutions.lastHeartbeatAt, heartbeatCutoff),\n ),\n );\n\n const staleIds = tx\n .select({id: runningJobExecutions.id})\n .from(runningJobExecutions)\n .where(stalePredicate)\n .orderBy(\n asc(\n sql`CASE WHEN ${runningJobExecutions.firstHeartbeatAt} IS NULL AND ${runningJobExecutions.lastHeartbeatAt} <= ${runningJobExecutions.startedAt} THEN ${runningJobExecutions.startedAt} ELSE ${runningJobExecutions.lastHeartbeatAt} END`,\n ),\n )\n .limit(params.limit ?? 100)\n .for('update', {skipLocked: true});\n\n const deleted = await tx\n .delete(runningJobExecutions)\n .where(and(inArray(runningJobExecutions.id, staleIds), stalePredicate))\n .returning({\n workflowRunId: runningJobExecutions.workflowRunId,\n workflowRunAttemptId: runningJobExecutions.workflowRunAttemptId,\n jobId: runningJobExecutions.jobId,\n jobExecutionId: runningJobExecutions.jobExecutionId,\n });\n\n if (deleted.length === 0) return [];\n\n await tx.delete(pendingJobExecutions).where(\n inArray(\n pendingJobExecutions.jobExecutionId,\n deleted.map((row) => row.jobExecutionId),\n ),\n );\n\n await writeOutboxEvents<RunnersEventMap>(\n tx,\n runnersOutbox,\n deleted.map((row) => ({\n type: RUNNER_JOB_LEASE_EXPIRED,\n payload: {\n workflowRunId: row.workflowRunId,\n workflowRunAttemptId: row.workflowRunAttemptId,\n jobId: row.jobId,\n jobExecutionId: row.jobExecutionId,\n },\n })),\n );\n\n return deleted;\n });\n\n if (reaped.length > 0) jobExecutionLeaseExpiredCount.add(reaped.length);\n\n return reaped;\n}\n\nexport async function getJobExecutionQueueDepth(): Promise<{\n pendingJobExecutions: number;\n runningJobExecutions: number;\n}> {\n const [pending] = await db().select({value: count()}).from(pendingJobExecutions);\n const [running] = await db().select({value: count()}).from(runningJobExecutions);\n return {\n pendingJobExecutions: pending?.value ?? 0,\n runningJobExecutions: running?.value ?? 0,\n };\n}\n\nexport async function listActiveRunningJobExecutions(params: {\n workspaceId: string;\n windowSeconds: number;\n limit?: number;\n}): Promise<ActiveRunningJobExecution[]> {\n return await db()\n .select({\n jobId: runningJobExecutions.jobId,\n jobExecutionId: runningJobExecutions.jobExecutionId,\n workflowRunId: runningJobExecutions.workflowRunId,\n workflowRunAttemptId: runningJobExecutions.workflowRunAttemptId,\n projectId: runningJobExecutions.projectId,\n runnerSessionId: runningJobExecutions.runnerSessionId,\n provisionerId: runningJobExecutions.provisionerId,\n provisionedRunnerId: runningJobExecutions.provisionedRunnerId,\n requiredLabels: runningJobExecutions.requiredLabels,\n runnerLabels: runningJobExecutions.runnerLabels,\n startedAt: runningJobExecutions.startedAt,\n lastHeartbeatAt: runningJobExecutions.lastHeartbeatAt,\n })\n .from(runningJobExecutions)\n .where(\n and(\n eq(runningJobExecutions.workspaceId, params.workspaceId),\n sql`${runningJobExecutions.lastHeartbeatAt} > now() - (${params.windowSeconds} || ' seconds')::interval`,\n ),\n )\n .orderBy(desc(runningJobExecutions.lastHeartbeatAt), desc(runningJobExecutions.id))\n .limit(params.limit ?? 1000);\n}\n\nexport async function listRunningJobExecutionsByProvisionedRunnerTx(\n tx: Tx,\n params: {\n workspaceId: string;\n provisionerId: string;\n provisionedRunnerIds: string[];\n },\n): Promise<ProvisionedRunnerBoundJobExecution[]> {\n if (params.provisionedRunnerIds.length === 0) return [];\n\n const duplicateRows = await tx\n .select({\n provisionedRunnerId: runningJobExecutions.provisionedRunnerId,\n count: count(),\n })\n .from(runningJobExecutions)\n .where(\n and(\n eq(runningJobExecutions.workspaceId, params.workspaceId),\n eq(runningJobExecutions.provisionerId, params.provisionerId),\n inArray(runningJobExecutions.provisionedRunnerId, params.provisionedRunnerIds),\n ),\n )\n .groupBy(runningJobExecutions.provisionedRunnerId)\n .having(sql`count(*) > 1`);\n\n const duplicateProvisionedRunnerIds = duplicateRows.flatMap((row) =>\n row.provisionedRunnerId ? [row.provisionedRunnerId] : [],\n );\n if (duplicateProvisionedRunnerIds.length > 0) {\n logger().warn(\n {\n workspaceId: params.workspaceId,\n provisionerId: params.provisionerId,\n provisionedRunnerIds: duplicateProvisionedRunnerIds,\n },\n 'multiple running job executions are bound to the same provisioned runner',\n );\n }\n\n const result = await tx.execute<{\n workflowRunId: string;\n workflowRunAttemptId: string;\n jobId: string;\n jobExecutionId: string;\n provisionedRunnerId: string;\n startedAt: Date | string;\n lastHeartbeatAt: Date | string;\n cancellationRequestedAt: Date | string | null;\n }>(sql`\n SELECT DISTINCT ON (${runningJobExecutions.provisionedRunnerId})\n ${runningJobExecutions.workflowRunId} AS \"workflowRunId\",\n ${runningJobExecutions.workflowRunAttemptId} AS \"workflowRunAttemptId\",\n ${runningJobExecutions.jobId} AS \"jobId\",\n ${runningJobExecutions.jobExecutionId} AS \"jobExecutionId\",\n ${runningJobExecutions.provisionedRunnerId} AS \"provisionedRunnerId\",\n ${runningJobExecutions.startedAt} AS \"startedAt\",\n ${runningJobExecutions.lastHeartbeatAt} AS \"lastHeartbeatAt\",\n ${runningJobExecutions.cancellationRequestedAt} AS \"cancellationRequestedAt\"\n FROM ${runningJobExecutions}\n WHERE\n ${runningJobExecutions.workspaceId} = ${params.workspaceId}\n AND ${runningJobExecutions.provisionerId} = ${params.provisionerId}\n AND ${runningJobExecutions.provisionedRunnerId} IN (${sql.join(\n params.provisionedRunnerIds.map((provisionedRunnerId) => sql`${provisionedRunnerId}`),\n sql`, `,\n )})\n ORDER BY ${runningJobExecutions.provisionedRunnerId}, ${runningJobExecutions.startedAt} DESC, ${runningJobExecutions.jobExecutionId} DESC\n `);\n\n return result.rows.map((row) => ({\n workflowRunId: row.workflowRunId,\n workflowRunAttemptId: row.workflowRunAttemptId,\n jobId: row.jobId,\n jobExecutionId: row.jobExecutionId,\n provisionedRunnerId: row.provisionedRunnerId,\n startedAt: toDate(row.startedAt),\n lastHeartbeatAt: toDate(row.lastHeartbeatAt),\n cancellationRequestedAt: row.cancellationRequestedAt\n ? toDate(row.cancellationRequestedAt)\n : null,\n }));\n}\n\nfunction toDate(value: Date | string): Date {\n return value instanceof Date ? value : new Date(value);\n}\n\nexport async function isJobLeaseActive(params: {\n jobId?: string;\n jobExecutionId: string;\n runnerSessionId: string;\n}): Promise<boolean> {\n const [row] = await db()\n .select({id: runningJobExecutions.id})\n .from(runningJobExecutions)\n .where(\n and(\n eq(runningJobExecutions.jobExecutionId, params.jobExecutionId),\n eq(runningJobExecutions.runnerSessionId, params.runnerSessionId),\n params.jobId === undefined ? undefined : eq(runningJobExecutions.jobId, params.jobId),\n ),\n )\n .limit(1);\n\n return row !== undefined;\n}\n\nexport async function recordHeartbeat(params: {\n jobExecutionId: string;\n runnerSessionId: string;\n toolCapabilities?: RunnerToolCapabilitiesDto | null;\n}): Promise<{\n cancellationRequested: boolean;\n previousToolCapabilities: RunnerToolCapabilitiesDto | null;\n currentToolCapabilities: RunnerToolCapabilitiesDto | null;\n runningJobExecution: {\n workflowRunId: string;\n workflowRunAttemptId: string;\n jobId: string;\n jobExecutionId: string;\n projectId: string;\n workspaceId: string;\n runnerSessionId: string;\n };\n}> {\n const result = await db().transaction(async (tx) => {\n const updated = await tx\n .update(runningJobExecutions)\n .set({\n firstHeartbeatAt: sql`COALESCE(${runningJobExecutions.firstHeartbeatAt}, now())`,\n lastHeartbeatAt: sql`now()`,\n })\n .where(\n and(\n eq(runningJobExecutions.jobExecutionId, params.jobExecutionId),\n eq(runningJobExecutions.runnerSessionId, params.runnerSessionId),\n ),\n )\n .returning({\n cancellationRequestedAt: runningJobExecutions.cancellationRequestedAt,\n workflowRunId: runningJobExecutions.workflowRunId,\n workflowRunAttemptId: runningJobExecutions.workflowRunAttemptId,\n jobId: runningJobExecutions.jobId,\n jobExecutionId: runningJobExecutions.jobExecutionId,\n projectId: runningJobExecutions.projectId,\n workspaceId: runningJobExecutions.workspaceId,\n runnerSessionId: runningJobExecutions.runnerSessionId,\n });\n\n const row = updated[0];\n if (!row) throw new RunningJobExecutionNotFoundError(params.jobExecutionId);\n\n const [previous] = await tx\n .select({toolCapabilities: runnerSessions.toolCapabilities})\n .from(runnerSessions)\n .where(eq(runnerSessions.id, params.runnerSessionId))\n .limit(1)\n .for('update');\n\n const [session] = await tx\n .update(runnerSessions)\n .set({\n toolCapabilities: params.toolCapabilities ?? null,\n toolCapabilitiesReportedAt: params.toolCapabilities ? sql`now()` : null,\n updatedAt: sql`now()`,\n })\n .where(eq(runnerSessions.id, params.runnerSessionId))\n .returning({toolCapabilities: runnerSessions.toolCapabilities});\n\n return {\n row,\n previousToolCapabilities: previous?.toolCapabilities ?? null,\n currentToolCapabilities: session?.toolCapabilities ?? null,\n };\n });\n\n const row = result.row;\n if (!row) throw new RunningJobExecutionNotFoundError(params.jobExecutionId);\n return {\n cancellationRequested: row.cancellationRequestedAt !== null,\n previousToolCapabilities: result.previousToolCapabilities,\n currentToolCapabilities: result.currentToolCapabilities,\n runningJobExecution: {\n workflowRunId: row.workflowRunId,\n workflowRunAttemptId: row.workflowRunAttemptId,\n jobId: row.jobId,\n jobExecutionId: row.jobExecutionId,\n projectId: row.projectId,\n workspaceId: row.workspaceId,\n runnerSessionId: row.runnerSessionId,\n },\n };\n}\n\nexport async function requestJobExecutionCancellation(params: {\n jobExecutionId: string;\n}): Promise<void> {\n await db()\n .update(runningJobExecutions)\n .set({\n cancellationRequestedAt: sql`COALESCE(${runningJobExecutions.cancellationRequestedAt}, now())`,\n })\n .where(eq(runningJobExecutions.jobExecutionId, params.jobExecutionId));\n}\n\nexport async function cancelRunnerJobs(params: {jobIds: string[]}): Promise<void> {\n if (params.jobIds.length === 0) return;\n\n await db().transaction(async (tx) => {\n await tx.delete(pendingJobExecutions).where(inArray(pendingJobExecutions.jobId, params.jobIds));\n await tx\n .update(runningJobExecutions)\n .set({\n cancellationRequestedAt: sql`COALESCE(${runningJobExecutions.cancellationRequestedAt}, now())`,\n })\n .where(inArray(runningJobExecutions.jobId, params.jobIds));\n });\n}\n"],"names":["RUNNER_JOB_CLAIMED","RUNNER_JOB_LEASE_EXPIRED","RUNNER_JOB_QUEUED","logger","writeOutboxEvent","writeOutboxEvents","canonicalizeLabels","and","arrayContained","asc","count","desc","eq","gt","inArray","isNotNull","isNull","lt","lte","or","sql","EmptyRequiredLabelsError","RunnerSessionExhaustedError","RunningJobExecutionNotFoundError","jobExecutionEnqueuedCount","jobExecutionLeaseExpiredCount","db","runnersOutbox","pendingJobExecutions","runnerSessions","runningJobExecutions","enqueueJobExecution","params","requiredLabels","length","enqueued","transaction","tx","inserted","insert","values","workspaceId","workflowRunId","workflowRunAttemptId","jobId","jobExecutionId","projectId","onConflictDoNothing","target","returning","createdAt","type","payload","queuedAt","toISOString","add","claimPendingJobExecution","touchRunnerSessionLiveness","runnerSessionId","throttleSeconds","runnerSessionLivenessThrottleSeconds","sessionLabels","provisionerId","provisionedRunnerId","maxClaims","session","select","claimsUsed","from","where","id","limit","for","row","orderBy","skipLocked","delete","runnerLabels","claimedAt","startedAt","claimed","update","set","updatedAt","releaseJobExecution","expireStuckJobExecutions","reaped","heartbeatCutoff","thresholdSeconds","firstHeartbeatCutoff","noFirstHeartbeatGraceSeconds","stalePredicate","firstHeartbeatAt","lastHeartbeatAt","staleIds","deleted","map","getJobExecutionQueueDepth","pending","value","running","listActiveRunningJobExecutions","windowSeconds","listRunningJobExecutionsByProvisionedRunnerTx","provisionedRunnerIds","duplicateRows","groupBy","having","duplicateProvisionedRunnerIds","flatMap","warn","result","execute","cancellationRequestedAt","join","rows","toDate","Date","isJobLeaseActive","undefined","recordHeartbeat","updated","previous","toolCapabilities","toolCapabilitiesReportedAt","previousToolCapabilities","currentToolCapabilities","cancellationRequested","runningJobExecution","requestJobExecutionCancellation","cancelRunnerJobs","jobIds"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/db/job-executions.ts"],"sourcesContent":["import {\n RUNNER_JOB_CLAIMED,\n RUNNER_JOB_LEASE_EXPIRED,\n RUNNER_JOB_QUEUED,\n type RunnersEventMap,\n type RunnerToolCapabilitiesDto,\n} from '@shipfox/api-runners-dto';\nimport {logger} from '@shipfox/node-opentelemetry';\nimport {writeOutboxEvent, writeOutboxEvents} from '@shipfox/node-outbox';\nimport {canonicalizeLabels} from '@shipfox/runner-labels';\nimport {\n and,\n arrayContained,\n asc,\n count,\n desc,\n eq,\n gt,\n inArray,\n isNotNull,\n isNull,\n lt,\n lte,\n or,\n sql,\n} from 'drizzle-orm';\nimport {\n EmptyRequiredLabelsError,\n RunnerSessionExhaustedError,\n RunningJobExecutionNotFoundError,\n} from '#core/errors.js';\nimport {jobExecutionEnqueuedCount, jobExecutionLeaseExpiredCount} from '#metrics/instance.js';\nimport type {Tx} from './db.js';\nimport {db} from './db.js';\nimport {runnersOutbox} from './schema/outbox.js';\nimport {pendingJobExecutions} from './schema/pending-job-executions.js';\nimport {runnerSessions} from './schema/runner-sessions.js';\nimport {runningJobExecutions} from './schema/running-job-executions.js';\n\nexport interface EnqueueJobExecutionParams {\n workspaceId: string;\n workflowRunId: string;\n workflowRunAttemptId: string;\n jobId: string;\n jobExecutionId: string;\n projectId: string;\n requiredLabels: string[];\n}\n\n// Idempotent while the job execution is still pending: a duplicate jobExecutionId already in\n// `runners_pending_jobs` is a no-op. Temporal retries the enqueue activity\n// at-least-once, so a unique-violation throw on a retry-after-lost-result\n// would permanently fail a healthy job execution's workflow. The guard does not extend\n// past the claim: once the job execution has moved to `runners_running_jobs`, a retry\n// can reinsert an orphan pending row, which a later `claimPendingJobExecution` drops\n// via the running-execution unique constraint (onConflictDoNothing) instead of failing.\nexport async function enqueueJobExecution(params: EnqueueJobExecutionParams): Promise<void> {\n const requiredLabels = [...canonicalizeLabels(params.requiredLabels)];\n if (requiredLabels.length === 0) throw new EmptyRequiredLabelsError();\n\n const enqueued = await db().transaction(async (tx) => {\n const [inserted] = await tx\n .insert(pendingJobExecutions)\n .values({\n workspaceId: params.workspaceId,\n workflowRunId: params.workflowRunId,\n workflowRunAttemptId: params.workflowRunAttemptId,\n jobId: params.jobId,\n jobExecutionId: params.jobExecutionId,\n projectId: params.projectId,\n requiredLabels,\n })\n .onConflictDoNothing({target: pendingJobExecutions.jobExecutionId})\n .returning({createdAt: pendingJobExecutions.createdAt});\n\n // A retry that hits the conflict inserts nothing: the first enqueue already\n // emitted the queued event (durably, in the outbox), so re-emitting would\n // only add a redundant row the subscriber coalesces away. Skip it.\n if (!inserted) return false;\n\n await writeOutboxEvent<RunnersEventMap>(tx, runnersOutbox, {\n type: RUNNER_JOB_QUEUED,\n payload: {\n workflowRunId: params.workflowRunId,\n workflowRunAttemptId: params.workflowRunAttemptId,\n jobId: params.jobId,\n jobExecutionId: params.jobExecutionId,\n queuedAt: inserted.createdAt.toISOString(),\n },\n });\n return true;\n });\n\n if (enqueued) jobExecutionEnqueuedCount.add(1);\n}\n\nexport interface ClaimedJobExecution {\n workflowRunId: string;\n workflowRunAttemptId: string;\n jobId: string;\n jobExecutionId: string;\n projectId: string;\n}\n\nexport interface ActiveRunningJobExecution {\n workflowRunId: string;\n workflowRunAttemptId: string;\n jobId: string;\n jobExecutionId: string;\n projectId: string;\n runnerSessionId: string;\n provisionerId: string | null;\n providerRunnerId: string | null;\n requiredLabels: string[];\n runnerLabels: string[];\n startedAt: Date;\n lastHeartbeatAt: Date;\n}\n\nexport interface RunnerInstanceBoundJobExecution {\n workflowRunId: string;\n workflowRunAttemptId: string;\n jobId: string;\n jobExecutionId: string;\n providerRunnerId: string;\n startedAt: Date;\n lastHeartbeatAt: Date;\n cancellationRequestedAt: Date | null;\n}\n\nexport async function claimPendingJobExecution(params: {\n workspaceId: string;\n runnerSessionId: string;\n sessionLabels: string[];\n maxClaims: number | null;\n runnerSessionLivenessThrottleSeconds: number;\n}): Promise<ClaimedJobExecution | null> {\n await touchRunnerSessionLiveness({\n workspaceId: params.workspaceId,\n runnerSessionId: params.runnerSessionId,\n throttleSeconds: params.runnerSessionLivenessThrottleSeconds,\n });\n\n if (params.sessionLabels.length === 0) return null;\n\n return await db().transaction(async (tx) => {\n let provisionerId: string | null = null;\n let providerRunnerId: string | null = null;\n\n if (params.maxClaims !== null) {\n const [session] = await tx\n .select({\n maxClaims: runnerSessions.maxClaims,\n claimsUsed: runnerSessions.claimsUsed,\n revokedAt: runnerSessions.revokedAt,\n provisionerId: runnerSessions.provisionerId,\n providerRunnerId: runnerSessions.providerRunnerId,\n })\n .from(runnerSessions)\n .where(eq(runnerSessions.id, params.runnerSessionId))\n .limit(1)\n .for('update');\n\n if (\n !session ||\n session.revokedAt ||\n session.maxClaims === null ||\n session.claimsUsed >= session.maxClaims\n ) {\n throw new RunnerSessionExhaustedError(params.runnerSessionId);\n }\n\n // Ephemeral sessions are the only capped sessions, and the DB check keeps\n // their provisioned-runner link present as a pair.\n provisionerId = session.provisionerId;\n providerRunnerId = session.providerRunnerId;\n }\n\n // `id` is a uuidv7 (time-ordered), so it is a deterministic FIFO tiebreaker\n // for rows sharing a created_at within a batch.\n const [row] = await tx\n .select()\n .from(pendingJobExecutions)\n .where(\n and(\n eq(pendingJobExecutions.workspaceId, params.workspaceId),\n arrayContained(pendingJobExecutions.requiredLabels, params.sessionLabels),\n ),\n )\n .orderBy(asc(pendingJobExecutions.createdAt), asc(pendingJobExecutions.id))\n .limit(1)\n .for('update', {skipLocked: true});\n\n if (!row) return null;\n\n await tx.delete(pendingJobExecutions).where(eq(pendingJobExecutions.id, row.id));\n\n // An enqueue retry that lands after a prior claim can leave an orphan pending\n // row whose jobExecutionId is already in `runners_running_jobs`. Insert-or-skip\n // on the jobExecutionId unique constraint: when the job execution is already running\n // the insert touches no row, so we commit the orphan's deletion and return\n // null rather than let the unique violation roll the claim back into a poison\n // loop. The runner just re-polls for a real job execution.\n const inserted = await tx\n .insert(runningJobExecutions)\n .values({\n workspaceId: row.workspaceId,\n workflowRunId: row.workflowRunId,\n workflowRunAttemptId: row.workflowRunAttemptId,\n jobId: row.jobId,\n jobExecutionId: row.jobExecutionId,\n projectId: row.projectId,\n runnerSessionId: params.runnerSessionId,\n provisionerId,\n providerRunnerId,\n requiredLabels: row.requiredLabels,\n runnerLabels: params.sessionLabels,\n })\n .onConflictDoNothing({target: runningJobExecutions.jobExecutionId})\n .returning({claimedAt: runningJobExecutions.startedAt});\n\n const claimed = inserted[0];\n if (!claimed) return null;\n\n if (params.maxClaims !== null) {\n await tx\n .update(runnerSessions)\n .set({claimsUsed: sql`${runnerSessions.claimsUsed} + 1`, updatedAt: sql`now()`})\n .where(eq(runnerSessions.id, params.runnerSessionId));\n }\n\n // The running-row insert is the runner claiming the job execution. Emit in the same tx; the\n // payload carries the row's own claim instant so a consumer records the true time,\n // not the outbox drain time.\n await writeOutboxEvent<RunnersEventMap>(tx, runnersOutbox, {\n type: RUNNER_JOB_CLAIMED,\n payload: {\n workflowRunId: row.workflowRunId,\n workflowRunAttemptId: row.workflowRunAttemptId,\n jobId: row.jobId,\n jobExecutionId: row.jobExecutionId,\n claimedAt: claimed.claimedAt.toISOString(),\n },\n });\n\n return {\n workflowRunId: row.workflowRunId,\n workflowRunAttemptId: row.workflowRunAttemptId,\n jobId: row.jobId,\n jobExecutionId: row.jobExecutionId,\n projectId: row.projectId,\n };\n });\n}\n\nasync function touchRunnerSessionLiveness(params: {\n workspaceId: string;\n runnerSessionId: string;\n throttleSeconds: number;\n}): Promise<void> {\n await db()\n .update(runnerSessions)\n .set({updatedAt: sql`now()`})\n .where(\n and(\n eq(runnerSessions.id, params.runnerSessionId),\n eq(runnerSessions.workspaceId, params.workspaceId),\n sql`${runnerSessions.updatedAt} < now() - (${params.throttleSeconds} || ' seconds')::interval`,\n ),\n );\n}\n\n/**\n * Releases a job execution's lease when the orchestration workflow finalizes it: deletes the\n * running-job-execution row AND any lingering pending row for the same execution, in one tx.\n * Idempotent (0-row no-op), no token scope (the workflow is authoritative), and\n * emits no event — the workflow already owns the outcome. Sweeping the pending row\n * too closes the at-least-once window where an enqueue retry left an orphan that a\n * later claim would otherwise pick up for an already-finished job execution.\n */\nexport async function releaseJobExecution(params: {jobExecutionId: string}): Promise<void> {\n await db().transaction(async (tx) => {\n // Delete pending before running to match `claimPendingJobExecution`'s lock-acquisition\n // order (it locks the pending row first, then the running row). A concurrent\n // claim picking up an orphan pending row for this same job execution would otherwise\n // deadlock against the reverse order here.\n await tx\n .delete(pendingJobExecutions)\n .where(eq(pendingJobExecutions.jobExecutionId, params.jobExecutionId));\n await tx\n .delete(runningJobExecutions)\n .where(eq(runningJobExecutions.jobExecutionId, params.jobExecutionId));\n });\n}\n\n/**\n * Reaps stale leases (bounded by `limit`), emitting one\n * `runners.job.lease_expired` event per reaped job execution.\n *\n * The cutoff is re-checked in the DELETE, not just the locking subquery, so a\n * heartbeat landing mid-call spares the live row. Each reaped execution also sweeps its\n * pending row: a failed best-effort `releaseJobExecution` would otherwise leave an orphan\n * that a later claim re-runs as an already-finished job execution.\n *\n * Locks running-then-pending, the inverse of `claimPendingJobExecution` / `releaseJobExecution`.\n * That pre-existing asymmetry opens a narrow deadlock window against a concurrent\n * claim of the same orphan-pending job execution; Postgres breaks it and the cron retries.\n */\nexport async function expireStuckJobExecutions(params: {\n thresholdSeconds: number;\n noFirstHeartbeatGraceSeconds: number;\n limit?: number;\n}): Promise<\n Array<{\n workflowRunId: string;\n workflowRunAttemptId: string;\n jobId: string;\n jobExecutionId: string;\n }>\n> {\n const reaped = await db().transaction(async (tx) => {\n const heartbeatCutoff = sql`now() - (${params.thresholdSeconds} || ' seconds')::interval`;\n const firstHeartbeatCutoff = sql`now() - (${params.noFirstHeartbeatGraceSeconds} || ' seconds')::interval`;\n const stalePredicate = or(\n and(\n isNull(runningJobExecutions.firstHeartbeatAt),\n lte(runningJobExecutions.lastHeartbeatAt, runningJobExecutions.startedAt),\n lt(runningJobExecutions.startedAt, firstHeartbeatCutoff),\n ),\n and(\n or(\n isNotNull(runningJobExecutions.firstHeartbeatAt),\n gt(runningJobExecutions.lastHeartbeatAt, runningJobExecutions.startedAt),\n ),\n lt(runningJobExecutions.lastHeartbeatAt, heartbeatCutoff),\n ),\n );\n\n const staleIds = tx\n .select({id: runningJobExecutions.id})\n .from(runningJobExecutions)\n .where(stalePredicate)\n .orderBy(\n asc(\n sql`CASE WHEN ${runningJobExecutions.firstHeartbeatAt} IS NULL AND ${runningJobExecutions.lastHeartbeatAt} <= ${runningJobExecutions.startedAt} THEN ${runningJobExecutions.startedAt} ELSE ${runningJobExecutions.lastHeartbeatAt} END`,\n ),\n )\n .limit(params.limit ?? 100)\n .for('update', {skipLocked: true});\n\n const deleted = await tx\n .delete(runningJobExecutions)\n .where(and(inArray(runningJobExecutions.id, staleIds), stalePredicate))\n .returning({\n workflowRunId: runningJobExecutions.workflowRunId,\n workflowRunAttemptId: runningJobExecutions.workflowRunAttemptId,\n jobId: runningJobExecutions.jobId,\n jobExecutionId: runningJobExecutions.jobExecutionId,\n });\n\n if (deleted.length === 0) return [];\n\n await tx.delete(pendingJobExecutions).where(\n inArray(\n pendingJobExecutions.jobExecutionId,\n deleted.map((row) => row.jobExecutionId),\n ),\n );\n\n await writeOutboxEvents<RunnersEventMap>(\n tx,\n runnersOutbox,\n deleted.map((row) => ({\n type: RUNNER_JOB_LEASE_EXPIRED,\n payload: {\n workflowRunId: row.workflowRunId,\n workflowRunAttemptId: row.workflowRunAttemptId,\n jobId: row.jobId,\n jobExecutionId: row.jobExecutionId,\n },\n })),\n );\n\n return deleted;\n });\n\n if (reaped.length > 0) jobExecutionLeaseExpiredCount.add(reaped.length);\n\n return reaped;\n}\n\nexport async function getJobExecutionQueueDepth(): Promise<{\n pendingJobExecutions: number;\n runningJobExecutions: number;\n}> {\n const [pending] = await db().select({value: count()}).from(pendingJobExecutions);\n const [running] = await db().select({value: count()}).from(runningJobExecutions);\n return {\n pendingJobExecutions: pending?.value ?? 0,\n runningJobExecutions: running?.value ?? 0,\n };\n}\n\nexport async function listActiveRunningJobExecutions(params: {\n workspaceId: string;\n windowSeconds: number;\n limit?: number;\n}): Promise<ActiveRunningJobExecution[]> {\n return await db()\n .select({\n jobId: runningJobExecutions.jobId,\n jobExecutionId: runningJobExecutions.jobExecutionId,\n workflowRunId: runningJobExecutions.workflowRunId,\n workflowRunAttemptId: runningJobExecutions.workflowRunAttemptId,\n projectId: runningJobExecutions.projectId,\n runnerSessionId: runningJobExecutions.runnerSessionId,\n provisionerId: runningJobExecutions.provisionerId,\n providerRunnerId: runningJobExecutions.providerRunnerId,\n requiredLabels: runningJobExecutions.requiredLabels,\n runnerLabels: runningJobExecutions.runnerLabels,\n startedAt: runningJobExecutions.startedAt,\n lastHeartbeatAt: runningJobExecutions.lastHeartbeatAt,\n })\n .from(runningJobExecutions)\n .where(\n and(\n eq(runningJobExecutions.workspaceId, params.workspaceId),\n sql`${runningJobExecutions.lastHeartbeatAt} > now() - (${params.windowSeconds} || ' seconds')::interval`,\n ),\n )\n .orderBy(desc(runningJobExecutions.lastHeartbeatAt), desc(runningJobExecutions.id))\n .limit(params.limit ?? 1000);\n}\n\nexport async function listRunningJobExecutionsByRunnerInstanceTx(\n tx: Tx,\n params: {\n workspaceId: string;\n provisionerId: string;\n providerRunnerIds: string[];\n },\n): Promise<RunnerInstanceBoundJobExecution[]> {\n if (params.providerRunnerIds.length === 0) return [];\n\n const duplicateRows = await tx\n .select({\n providerRunnerId: runningJobExecutions.providerRunnerId,\n count: count(),\n })\n .from(runningJobExecutions)\n .where(\n and(\n eq(runningJobExecutions.workspaceId, params.workspaceId),\n eq(runningJobExecutions.provisionerId, params.provisionerId),\n inArray(runningJobExecutions.providerRunnerId, params.providerRunnerIds),\n ),\n )\n .groupBy(runningJobExecutions.providerRunnerId)\n .having(sql`count(*) > 1`);\n\n const duplicateRunnerInstanceIds = duplicateRows.flatMap((row) =>\n row.providerRunnerId ? [row.providerRunnerId] : [],\n );\n if (duplicateRunnerInstanceIds.length > 0) {\n logger().warn(\n {\n workspaceId: params.workspaceId,\n provisionerId: params.provisionerId,\n providerRunnerIds: duplicateRunnerInstanceIds,\n },\n 'multiple running job executions are bound to the same provisioned runner',\n );\n }\n\n const result = await tx.execute<{\n workflowRunId: string;\n workflowRunAttemptId: string;\n jobId: string;\n jobExecutionId: string;\n providerRunnerId: string;\n startedAt: Date | string;\n lastHeartbeatAt: Date | string;\n cancellationRequestedAt: Date | string | null;\n }>(sql`\n SELECT DISTINCT ON (${runningJobExecutions.providerRunnerId})\n ${runningJobExecutions.workflowRunId} AS \"workflowRunId\",\n ${runningJobExecutions.workflowRunAttemptId} AS \"workflowRunAttemptId\",\n ${runningJobExecutions.jobId} AS \"jobId\",\n ${runningJobExecutions.jobExecutionId} AS \"jobExecutionId\",\n ${runningJobExecutions.providerRunnerId} AS \"providerRunnerId\",\n ${runningJobExecutions.startedAt} AS \"startedAt\",\n ${runningJobExecutions.lastHeartbeatAt} AS \"lastHeartbeatAt\",\n ${runningJobExecutions.cancellationRequestedAt} AS \"cancellationRequestedAt\"\n FROM ${runningJobExecutions}\n WHERE\n ${runningJobExecutions.workspaceId} = ${params.workspaceId}\n AND ${runningJobExecutions.provisionerId} = ${params.provisionerId}\n AND ${runningJobExecutions.providerRunnerId} IN (${sql.join(\n params.providerRunnerIds.map((providerRunnerId) => sql`${providerRunnerId}`),\n sql`, `,\n )})\n ORDER BY ${runningJobExecutions.providerRunnerId}, ${runningJobExecutions.startedAt} DESC, ${runningJobExecutions.jobExecutionId} DESC\n `);\n\n return result.rows.map((row) => ({\n workflowRunId: row.workflowRunId,\n workflowRunAttemptId: row.workflowRunAttemptId,\n jobId: row.jobId,\n jobExecutionId: row.jobExecutionId,\n providerRunnerId: row.providerRunnerId,\n startedAt: toDate(row.startedAt),\n lastHeartbeatAt: toDate(row.lastHeartbeatAt),\n cancellationRequestedAt: row.cancellationRequestedAt\n ? toDate(row.cancellationRequestedAt)\n : null,\n }));\n}\n\nfunction toDate(value: Date | string): Date {\n return value instanceof Date ? value : new Date(value);\n}\n\nexport async function isJobLeaseActive(params: {\n jobId?: string;\n jobExecutionId: string;\n runnerSessionId: string;\n}): Promise<boolean> {\n const [row] = await db()\n .select({id: runningJobExecutions.id})\n .from(runningJobExecutions)\n .where(\n and(\n eq(runningJobExecutions.jobExecutionId, params.jobExecutionId),\n eq(runningJobExecutions.runnerSessionId, params.runnerSessionId),\n params.jobId === undefined ? undefined : eq(runningJobExecutions.jobId, params.jobId),\n ),\n )\n .limit(1);\n\n return row !== undefined;\n}\n\nexport async function recordHeartbeat(params: {\n jobExecutionId: string;\n runnerSessionId: string;\n toolCapabilities?: RunnerToolCapabilitiesDto | null;\n}): Promise<{\n cancellationRequested: boolean;\n previousToolCapabilities: RunnerToolCapabilitiesDto | null;\n currentToolCapabilities: RunnerToolCapabilitiesDto | null;\n runningJobExecution: {\n workflowRunId: string;\n workflowRunAttemptId: string;\n jobId: string;\n jobExecutionId: string;\n projectId: string;\n workspaceId: string;\n runnerSessionId: string;\n };\n}> {\n const result = await db().transaction(async (tx) => {\n const updated = await tx\n .update(runningJobExecutions)\n .set({\n firstHeartbeatAt: sql`COALESCE(${runningJobExecutions.firstHeartbeatAt}, now())`,\n lastHeartbeatAt: sql`now()`,\n })\n .where(\n and(\n eq(runningJobExecutions.jobExecutionId, params.jobExecutionId),\n eq(runningJobExecutions.runnerSessionId, params.runnerSessionId),\n ),\n )\n .returning({\n cancellationRequestedAt: runningJobExecutions.cancellationRequestedAt,\n workflowRunId: runningJobExecutions.workflowRunId,\n workflowRunAttemptId: runningJobExecutions.workflowRunAttemptId,\n jobId: runningJobExecutions.jobId,\n jobExecutionId: runningJobExecutions.jobExecutionId,\n projectId: runningJobExecutions.projectId,\n workspaceId: runningJobExecutions.workspaceId,\n runnerSessionId: runningJobExecutions.runnerSessionId,\n });\n\n const row = updated[0];\n if (!row) throw new RunningJobExecutionNotFoundError(params.jobExecutionId);\n\n const [previous] = await tx\n .select({toolCapabilities: runnerSessions.toolCapabilities})\n .from(runnerSessions)\n .where(eq(runnerSessions.id, params.runnerSessionId))\n .limit(1)\n .for('update');\n\n const [session] = await tx\n .update(runnerSessions)\n .set({\n toolCapabilities: params.toolCapabilities ?? null,\n toolCapabilitiesReportedAt: params.toolCapabilities ? sql`now()` : null,\n updatedAt: sql`now()`,\n })\n .where(eq(runnerSessions.id, params.runnerSessionId))\n .returning({toolCapabilities: runnerSessions.toolCapabilities});\n\n return {\n row,\n previousToolCapabilities: previous?.toolCapabilities ?? null,\n currentToolCapabilities: session?.toolCapabilities ?? null,\n };\n });\n\n const row = result.row;\n if (!row) throw new RunningJobExecutionNotFoundError(params.jobExecutionId);\n return {\n cancellationRequested: row.cancellationRequestedAt !== null,\n previousToolCapabilities: result.previousToolCapabilities,\n currentToolCapabilities: result.currentToolCapabilities,\n runningJobExecution: {\n workflowRunId: row.workflowRunId,\n workflowRunAttemptId: row.workflowRunAttemptId,\n jobId: row.jobId,\n jobExecutionId: row.jobExecutionId,\n projectId: row.projectId,\n workspaceId: row.workspaceId,\n runnerSessionId: row.runnerSessionId,\n },\n };\n}\n\nexport async function requestJobExecutionCancellation(params: {\n jobExecutionId: string;\n}): Promise<void> {\n await db()\n .update(runningJobExecutions)\n .set({\n cancellationRequestedAt: sql`COALESCE(${runningJobExecutions.cancellationRequestedAt}, now())`,\n })\n .where(eq(runningJobExecutions.jobExecutionId, params.jobExecutionId));\n}\n\nexport async function cancelRunnerJobs(params: {jobIds: string[]}): Promise<void> {\n if (params.jobIds.length === 0) return;\n\n await db().transaction(async (tx) => {\n await tx.delete(pendingJobExecutions).where(inArray(pendingJobExecutions.jobId, params.jobIds));\n await tx\n .update(runningJobExecutions)\n .set({\n cancellationRequestedAt: sql`COALESCE(${runningJobExecutions.cancellationRequestedAt}, now())`,\n })\n .where(inArray(runningJobExecutions.jobId, params.jobIds));\n });\n}\n"],"names":["RUNNER_JOB_CLAIMED","RUNNER_JOB_LEASE_EXPIRED","RUNNER_JOB_QUEUED","logger","writeOutboxEvent","writeOutboxEvents","canonicalizeLabels","and","arrayContained","asc","count","desc","eq","gt","inArray","isNotNull","isNull","lt","lte","or","sql","EmptyRequiredLabelsError","RunnerSessionExhaustedError","RunningJobExecutionNotFoundError","jobExecutionEnqueuedCount","jobExecutionLeaseExpiredCount","db","runnersOutbox","pendingJobExecutions","runnerSessions","runningJobExecutions","enqueueJobExecution","params","requiredLabels","length","enqueued","transaction","tx","inserted","insert","values","workspaceId","workflowRunId","workflowRunAttemptId","jobId","jobExecutionId","projectId","onConflictDoNothing","target","returning","createdAt","type","payload","queuedAt","toISOString","add","claimPendingJobExecution","touchRunnerSessionLiveness","runnerSessionId","throttleSeconds","runnerSessionLivenessThrottleSeconds","sessionLabels","provisionerId","providerRunnerId","maxClaims","session","select","claimsUsed","revokedAt","from","where","id","limit","for","row","orderBy","skipLocked","delete","runnerLabels","claimedAt","startedAt","claimed","update","set","updatedAt","releaseJobExecution","expireStuckJobExecutions","reaped","heartbeatCutoff","thresholdSeconds","firstHeartbeatCutoff","noFirstHeartbeatGraceSeconds","stalePredicate","firstHeartbeatAt","lastHeartbeatAt","staleIds","deleted","map","getJobExecutionQueueDepth","pending","value","running","listActiveRunningJobExecutions","windowSeconds","listRunningJobExecutionsByRunnerInstanceTx","providerRunnerIds","duplicateRows","groupBy","having","duplicateRunnerInstanceIds","flatMap","warn","result","execute","cancellationRequestedAt","join","rows","toDate","Date","isJobLeaseActive","undefined","recordHeartbeat","updated","previous","toolCapabilities","toolCapabilitiesReportedAt","previousToolCapabilities","currentToolCapabilities","cancellationRequested","runningJobExecution","requestJobExecutionCancellation","cancelRunnerJobs","jobIds"],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ProvisionerCapabilitySnapshot } from '#core/entities/provisioner-capability-snapshot.js';
|
|
2
|
+
import type { ReservationTemplate } from './reservations.js';
|
|
3
|
+
export declare function publishWorkspaceProvisionerCapabilitySnapshot(params: {
|
|
4
|
+
workspaceId: string;
|
|
5
|
+
provisionerId: string;
|
|
6
|
+
templates: ReservationTemplate[];
|
|
7
|
+
}): Promise<void>;
|
|
8
|
+
export declare function listActiveWorkspaceProvisionerCapabilitySnapshots(params: {
|
|
9
|
+
workspaceId: string;
|
|
10
|
+
windowSeconds: number;
|
|
11
|
+
}): Promise<ProvisionerCapabilitySnapshot[]>;
|
|
12
|
+
export declare function listStaleWorkspaceProvisionerCapabilitySnapshots(params: {
|
|
13
|
+
workspaceId: string;
|
|
14
|
+
windowSeconds: number;
|
|
15
|
+
}): Promise<ProvisionerCapabilitySnapshot[]>;
|
|
16
|
+
export declare function hasActiveWorkspaceProvisionerCapability(params: {
|
|
17
|
+
workspaceId: string;
|
|
18
|
+
requiredLabels: string[];
|
|
19
|
+
windowSeconds: number;
|
|
20
|
+
}): Promise<boolean>;
|
|
21
|
+
//# sourceMappingURL=provisioner-capability-snapshots.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provisioner-capability-snapshots.d.ts","sourceRoot":"","sources":["../../src/db/provisioner-capability-snapshots.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,6BAA6B,EAAC,MAAM,mDAAmD,CAAC;AAErG,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,mBAAmB,CAAC;AAO3D,wBAAsB,6CAA6C,CAAC,MAAM,EAAE;IAC1E,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,mBAAmB,EAAE,CAAC;CAClC,GAAG,OAAO,CAAC,IAAI,CAAC,CAoBhB;AAED,wBAAsB,iDAAiD,CAAC,MAAM,EAAE;IAC9E,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;CACvB,GAAG,OAAO,CAAC,6BAA6B,EAAE,CAAC,CAW3C;AAED,wBAAsB,gDAAgD,CAAC,MAAM,EAAE;IAC7E,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;CACvB,GAAG,OAAO,CAAC,6BAA6B,EAAE,CAAC,CAwB3C;AAED,wBAAsB,uCAAuC,CAAC,MAAM,EAAE;IACpE,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,aAAa,EAAE,MAAM,CAAC;CACvB,GAAG,OAAO,CAAC,OAAO,CAAC,CAmBnB"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { canonicalizeLabels } from '@shipfox/runner-labels';
|
|
2
|
+
import { and, arrayContains, eq, gt, isNotNull, isNull, lte, or, sql } from 'drizzle-orm';
|
|
3
|
+
import { db } from './db.js';
|
|
4
|
+
import { provisionerCapabilitySnapshots, toProvisionerCapabilitySnapshot } from './schema/provisioner-capability-snapshots.js';
|
|
5
|
+
import { provisionerTokens } from './schema/provisioner-tokens.js';
|
|
6
|
+
export async function publishWorkspaceProvisionerCapabilitySnapshot(params) {
|
|
7
|
+
await db().transaction(async (tx)=>{
|
|
8
|
+
await tx.delete(provisionerCapabilitySnapshots).where(eq(provisionerCapabilitySnapshots.provisionerId, params.provisionerId));
|
|
9
|
+
if (params.templates.length === 0) return;
|
|
10
|
+
await tx.insert(provisionerCapabilitySnapshots).values(params.templates.map((template)=>({
|
|
11
|
+
workspaceId: params.workspaceId,
|
|
12
|
+
provisionerId: params.provisionerId,
|
|
13
|
+
templateKey: template.templateKey,
|
|
14
|
+
labels: [
|
|
15
|
+
...canonicalizeLabels(template.labels)
|
|
16
|
+
],
|
|
17
|
+
availableSlots: template.availableSlots,
|
|
18
|
+
starting: template.starting,
|
|
19
|
+
running: template.running
|
|
20
|
+
})));
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
export async function listActiveWorkspaceProvisionerCapabilitySnapshots(params) {
|
|
24
|
+
const rows = await db().select({
|
|
25
|
+
snapshot: provisionerCapabilitySnapshots
|
|
26
|
+
}).from(provisionerCapabilitySnapshots).innerJoin(provisionerTokens, eq(provisionerTokens.id, provisionerCapabilitySnapshots.provisionerId)).where(and(...activeWorkspaceProvisionerCapabilityConditions(params)));
|
|
27
|
+
return rows.map(({ snapshot })=>toProvisionerCapabilitySnapshot(snapshot));
|
|
28
|
+
}
|
|
29
|
+
export async function listStaleWorkspaceProvisionerCapabilitySnapshots(params) {
|
|
30
|
+
const rows = await db().select({
|
|
31
|
+
snapshot: provisionerCapabilitySnapshots
|
|
32
|
+
}).from(provisionerCapabilitySnapshots).innerJoin(provisionerTokens, eq(provisionerTokens.id, provisionerCapabilitySnapshots.provisionerId)).where(and(eq(provisionerCapabilitySnapshots.workspaceId, params.workspaceId), or(lte(provisionerCapabilitySnapshots.advertisedAt, sql`now() - (${params.windowSeconds} || ' seconds')::interval`), eq(provisionerTokens.scope, 'installation'), isNull(provisionerTokens.workspaceId), provisionerTokenIsUnavailable())));
|
|
33
|
+
return rows.map(({ snapshot })=>toProvisionerCapabilitySnapshot(snapshot));
|
|
34
|
+
}
|
|
35
|
+
export async function hasActiveWorkspaceProvisionerCapability(params) {
|
|
36
|
+
const [row] = await db().select({
|
|
37
|
+
id: provisionerCapabilitySnapshots.id
|
|
38
|
+
}).from(provisionerCapabilitySnapshots).innerJoin(provisionerTokens, eq(provisionerTokens.id, provisionerCapabilitySnapshots.provisionerId)).where(and(...activeWorkspaceProvisionerCapabilityConditions(params), arrayContains(provisionerCapabilitySnapshots.labels, [
|
|
39
|
+
...canonicalizeLabels(params.requiredLabels)
|
|
40
|
+
]))).limit(1);
|
|
41
|
+
return row !== undefined;
|
|
42
|
+
}
|
|
43
|
+
function activeWorkspaceProvisionerCapabilityConditions(params) {
|
|
44
|
+
return [
|
|
45
|
+
eq(provisionerCapabilitySnapshots.workspaceId, params.workspaceId),
|
|
46
|
+
eq(provisionerTokens.workspaceId, params.workspaceId),
|
|
47
|
+
eq(provisionerTokens.scope, 'workspace'),
|
|
48
|
+
isNull(provisionerTokens.revokedAt),
|
|
49
|
+
or(isNull(provisionerTokens.expiresAt), gt(provisionerTokens.expiresAt, sql`now()`)),
|
|
50
|
+
gt(provisionerCapabilitySnapshots.advertisedAt, sql`now() - (${params.windowSeconds} || ' seconds')::interval`)
|
|
51
|
+
];
|
|
52
|
+
}
|
|
53
|
+
function provisionerTokenIsUnavailable() {
|
|
54
|
+
return or(isNotNull(provisionerTokens.revokedAt), and(isNotNull(provisionerTokens.expiresAt), lte(provisionerTokens.expiresAt, sql`now()`)));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
//# sourceMappingURL=provisioner-capability-snapshots.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/db/provisioner-capability-snapshots.ts"],"sourcesContent":["import {canonicalizeLabels} from '@shipfox/runner-labels';\nimport {and, arrayContains, eq, gt, isNotNull, isNull, lte, or, sql} from 'drizzle-orm';\nimport type {ProvisionerCapabilitySnapshot} from '#core/entities/provisioner-capability-snapshot.js';\nimport {db} from './db.js';\nimport type {ReservationTemplate} from './reservations.js';\nimport {\n provisionerCapabilitySnapshots,\n toProvisionerCapabilitySnapshot,\n} from './schema/provisioner-capability-snapshots.js';\nimport {provisionerTokens} from './schema/provisioner-tokens.js';\n\nexport async function publishWorkspaceProvisionerCapabilitySnapshot(params: {\n workspaceId: string;\n provisionerId: string;\n templates: ReservationTemplate[];\n}): Promise<void> {\n await db().transaction(async (tx) => {\n await tx\n .delete(provisionerCapabilitySnapshots)\n .where(eq(provisionerCapabilitySnapshots.provisionerId, params.provisionerId));\n\n if (params.templates.length === 0) return;\n\n await tx.insert(provisionerCapabilitySnapshots).values(\n params.templates.map((template) => ({\n workspaceId: params.workspaceId,\n provisionerId: params.provisionerId,\n templateKey: template.templateKey,\n labels: [...canonicalizeLabels(template.labels)],\n availableSlots: template.availableSlots,\n starting: template.starting,\n running: template.running,\n })),\n );\n });\n}\n\nexport async function listActiveWorkspaceProvisionerCapabilitySnapshots(params: {\n workspaceId: string;\n windowSeconds: number;\n}): Promise<ProvisionerCapabilitySnapshot[]> {\n const rows = await db()\n .select({snapshot: provisionerCapabilitySnapshots})\n .from(provisionerCapabilitySnapshots)\n .innerJoin(\n provisionerTokens,\n eq(provisionerTokens.id, provisionerCapabilitySnapshots.provisionerId),\n )\n .where(and(...activeWorkspaceProvisionerCapabilityConditions(params)));\n\n return rows.map(({snapshot}) => toProvisionerCapabilitySnapshot(snapshot));\n}\n\nexport async function listStaleWorkspaceProvisionerCapabilitySnapshots(params: {\n workspaceId: string;\n windowSeconds: number;\n}): Promise<ProvisionerCapabilitySnapshot[]> {\n const rows = await db()\n .select({snapshot: provisionerCapabilitySnapshots})\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 or(\n lte(\n provisionerCapabilitySnapshots.advertisedAt,\n sql`now() - (${params.windowSeconds} || ' seconds')::interval`,\n ),\n eq(provisionerTokens.scope, 'installation'),\n isNull(provisionerTokens.workspaceId),\n provisionerTokenIsUnavailable(),\n ),\n ),\n );\n\n return rows.map(({snapshot}) => toProvisionerCapabilitySnapshot(snapshot));\n}\n\nexport async function hasActiveWorkspaceProvisionerCapability(params: {\n workspaceId: string;\n requiredLabels: string[];\n windowSeconds: number;\n}): Promise<boolean> {\n const [row] = await db()\n .select({id: provisionerCapabilitySnapshots.id})\n .from(provisionerCapabilitySnapshots)\n .innerJoin(\n provisionerTokens,\n eq(provisionerTokens.id, provisionerCapabilitySnapshots.provisionerId),\n )\n .where(\n and(\n ...activeWorkspaceProvisionerCapabilityConditions(params),\n arrayContains(provisionerCapabilitySnapshots.labels, [\n ...canonicalizeLabels(params.requiredLabels),\n ]),\n ),\n )\n .limit(1);\n\n return row !== undefined;\n}\n\nfunction activeWorkspaceProvisionerCapabilityConditions(params: {\n workspaceId: string;\n windowSeconds: number;\n}) {\n return [\n eq(provisionerCapabilitySnapshots.workspaceId, params.workspaceId),\n eq(provisionerTokens.workspaceId, params.workspaceId),\n eq(provisionerTokens.scope, 'workspace' as const),\n isNull(provisionerTokens.revokedAt),\n or(isNull(provisionerTokens.expiresAt), gt(provisionerTokens.expiresAt, sql`now()`)),\n gt(\n provisionerCapabilitySnapshots.advertisedAt,\n sql`now() - (${params.windowSeconds} || ' seconds')::interval`,\n ),\n ];\n}\n\nfunction provisionerTokenIsUnavailable() {\n return or(\n isNotNull(provisionerTokens.revokedAt),\n and(isNotNull(provisionerTokens.expiresAt), lte(provisionerTokens.expiresAt, sql`now()`)),\n );\n}\n"],"names":["canonicalizeLabels","and","arrayContains","eq","gt","isNotNull","isNull","lte","or","sql","db","provisionerCapabilitySnapshots","toProvisionerCapabilitySnapshot","provisionerTokens","publishWorkspaceProvisionerCapabilitySnapshot","params","transaction","tx","delete","where","provisionerId","templates","length","insert","values","map","template","workspaceId","templateKey","labels","availableSlots","starting","running","listActiveWorkspaceProvisionerCapabilitySnapshots","rows","select","snapshot","from","innerJoin","id","activeWorkspaceProvisionerCapabilityConditions","listStaleWorkspaceProvisionerCapabilitySnapshots","advertisedAt","windowSeconds","scope","provisionerTokenIsUnavailable","hasActiveWorkspaceProvisionerCapability","row","requiredLabels","limit","undefined","revokedAt","expiresAt"],"mappings":"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"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import type { ActiveProvisionerToken, ProvisionerToken } from '#core/entities/provisioner-token.js';
|
|
1
|
+
import type { ActiveProvisionerToken, ProvisionerScope, ProvisionerToken } from '#core/entities/provisioner-token.js';
|
|
2
2
|
export interface CreateProvisionerTokenParams {
|
|
3
|
-
|
|
3
|
+
scope: ProvisionerScope;
|
|
4
|
+
workspaceId?: string | undefined;
|
|
4
5
|
hashedToken: string;
|
|
5
6
|
prefix: string;
|
|
6
7
|
createdByUserId: string;
|
|
@@ -8,6 +9,10 @@ export interface CreateProvisionerTokenParams {
|
|
|
8
9
|
expiresAt?: Date | undefined;
|
|
9
10
|
}
|
|
10
11
|
export declare function createProvisionerToken(params: CreateProvisionerTokenParams): Promise<ProvisionerToken>;
|
|
12
|
+
export declare function revokeInstallationProvisionerToken(params: {
|
|
13
|
+
tokenId: string;
|
|
14
|
+
revokedByUserId: string;
|
|
15
|
+
}): Promise<ProvisionerToken | undefined>;
|
|
11
16
|
export declare function listUsableProvisionerTokensByWorkspaceId(workspaceId: string): Promise<ProvisionerToken[]>;
|
|
12
17
|
export declare function resolveProvisionerTokenByHash(hashedToken: string): Promise<ProvisionerToken | undefined>;
|
|
13
18
|
export declare function revokeProvisionerToken(params: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provisioner-tokens.d.ts","sourceRoot":"","sources":["../../src/db/provisioner-tokens.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"provisioner-tokens.d.ts","sourceRoot":"","sources":["../../src/db/provisioner-tokens.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,sBAAsB,EACtB,gBAAgB,EAChB,gBAAgB,EACjB,MAAM,qCAAqC,CAAC;AAQ7C,MAAM,WAAW,4BAA4B;IAC3C,KAAK,EAAE,gBAAgB,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,MAAM,CAAC;IACxB,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,SAAS,CAAC,EAAE,IAAI,GAAG,SAAS,CAAC;CAC9B;AAwDD,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,4BAA4B,GACnC,OAAO,CAAC,gBAAgB,CAAC,CAiB3B;AAED,wBAAsB,kCAAkC,CAAC,MAAM,EAAE;IAC/D,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,EAAE,MAAM,CAAC;CACzB,GAAG,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC,CA+BxC;AAED,wBAAsB,wCAAwC,CAC5D,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAgB7B;AAED,wBAAsB,6BAA6B,CACjD,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC,CAUvC;AAED,wBAAsB,sBAAsB,CAAC,MAAM,EAAE;IACnD,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;CACzB,GAAG,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC,CAoCxC;AAED,wBAAsB,wBAAwB,CAAC,MAAM,EAAE;IACrD,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,EAAE,MAAM,CAAC;CACzB,GAAG,OAAO,CAAC,IAAI,CAAC,CAahB;AAED,wBAAsB,2BAA2B,CAAC,MAAM,EAAE;IACxD,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;CACvB,GAAG,OAAO,CAAC,sBAAsB,EAAE,CAAC,CAkBpC"}
|
|
@@ -1,9 +1,36 @@
|
|
|
1
|
-
import { and, desc, eq, gt, isNull, or, sql } from 'drizzle-orm';
|
|
1
|
+
import { and, desc, eq, gt, inArray, isNull, or, sql } from 'drizzle-orm';
|
|
2
2
|
import { db } from './db.js';
|
|
3
3
|
import { provisionerTokens, toProvisionerToken } from './schema/provisioner-tokens.js';
|
|
4
|
+
import { runnerActivationTokens } from './schema/runner-activation-tokens.js';
|
|
5
|
+
import { runnerBootstrapTokens, runnerControlSessions } from './schema/runner-control-sessions.js';
|
|
6
|
+
import { providerRunners } from './schema/runner-instances.js';
|
|
7
|
+
import { runnerSessions } from './schema/runner-sessions.js';
|
|
8
|
+
async function cascadeProvisionerRevocation(tx, provisionerId) {
|
|
9
|
+
await tx.update(runnerBootstrapTokens).set({
|
|
10
|
+
revokedAt: sql`now()`
|
|
11
|
+
}).where(eq(runnerBootstrapTokens.provisionerId, provisionerId));
|
|
12
|
+
await tx.update(runnerControlSessions).set({
|
|
13
|
+
closedAt: sql`now()`,
|
|
14
|
+
closeReason: 'provisioner-revoked'
|
|
15
|
+
}).where(and(eq(runnerControlSessions.provisionerId, provisionerId), isNull(runnerControlSessions.closedAt)));
|
|
16
|
+
await tx.update(runnerActivationTokens).set({
|
|
17
|
+
revokedAt: sql`now()`
|
|
18
|
+
}).where(and(isNull(runnerActivationTokens.consumedAt), isNull(runnerActivationTokens.revokedAt), inArray(runnerActivationTokens.runnerInstanceId, tx.select({
|
|
19
|
+
id: providerRunners.id
|
|
20
|
+
}).from(providerRunners).where(eq(providerRunners.provisionerId, provisionerId)))));
|
|
21
|
+
await tx.update(providerRunners).set({
|
|
22
|
+
state: 'terminated',
|
|
23
|
+
terminatedAt: sql`now()`,
|
|
24
|
+
updatedAt: sql`now()`
|
|
25
|
+
}).where(and(eq(providerRunners.provisionerId, provisionerId), isNull(providerRunners.runnerSessionId)));
|
|
26
|
+
await tx.update(runnerSessions).set({
|
|
27
|
+
revokedAt: sql`now()`
|
|
28
|
+
}).where(and(eq(runnerSessions.provisionerId, provisionerId), eq(runnerSessions.claimsUsed, 0), isNull(runnerSessions.revokedAt)));
|
|
29
|
+
}
|
|
4
30
|
export async function createProvisionerToken(params) {
|
|
5
31
|
const rows = await db().insert(provisionerTokens).values({
|
|
6
|
-
|
|
32
|
+
scope: params.scope,
|
|
33
|
+
workspaceId: params.workspaceId ?? null,
|
|
7
34
|
hashedToken: params.hashedToken,
|
|
8
35
|
prefix: params.prefix,
|
|
9
36
|
createdByUserId: params.createdByUserId,
|
|
@@ -14,9 +41,27 @@ export async function createProvisionerToken(params) {
|
|
|
14
41
|
if (!row) throw new Error('Insert returned no rows');
|
|
15
42
|
return toProvisionerToken(row);
|
|
16
43
|
}
|
|
44
|
+
export async function revokeInstallationProvisionerToken(params) {
|
|
45
|
+
const rows = await db().transaction(async (tx)=>{
|
|
46
|
+
const rows = await tx.update(provisionerTokens).set({
|
|
47
|
+
revokedAt: new Date(),
|
|
48
|
+
revokedByUserId: params.revokedByUserId,
|
|
49
|
+
updatedAt: new Date()
|
|
50
|
+
}).where(and(eq(provisionerTokens.id, params.tokenId), eq(provisionerTokens.scope, 'installation'), isNull(provisionerTokens.revokedAt))).returning();
|
|
51
|
+
if (rows[0]) {
|
|
52
|
+
await cascadeProvisionerRevocation(tx, params.tokenId);
|
|
53
|
+
}
|
|
54
|
+
return rows;
|
|
55
|
+
});
|
|
56
|
+
const row = rows[0];
|
|
57
|
+
if (row) return toProvisionerToken(row);
|
|
58
|
+
const existingRows = await db().select().from(provisionerTokens).where(and(eq(provisionerTokens.id, params.tokenId), eq(provisionerTokens.scope, 'installation'))).limit(1);
|
|
59
|
+
const existingRow = existingRows[0];
|
|
60
|
+
return existingRow ? toProvisionerToken(existingRow) : undefined;
|
|
61
|
+
}
|
|
17
62
|
export async function listUsableProvisionerTokensByWorkspaceId(workspaceId) {
|
|
18
63
|
const now = new Date();
|
|
19
|
-
const rows = await db().select().from(provisionerTokens).where(and(eq(provisionerTokens.workspaceId, workspaceId), isNull(provisionerTokens.revokedAt), or(isNull(provisionerTokens.expiresAt), gt(provisionerTokens.expiresAt, now)))).orderBy(desc(provisionerTokens.createdAt), desc(provisionerTokens.id));
|
|
64
|
+
const rows = await db().select().from(provisionerTokens).where(and(eq(provisionerTokens.workspaceId, workspaceId), eq(provisionerTokens.scope, 'workspace'), isNull(provisionerTokens.revokedAt), or(isNull(provisionerTokens.expiresAt), gt(provisionerTokens.expiresAt, now)))).orderBy(desc(provisionerTokens.createdAt), desc(provisionerTokens.id));
|
|
20
65
|
return rows.map(toProvisionerToken);
|
|
21
66
|
}
|
|
22
67
|
export async function resolveProvisionerTokenByHash(hashedToken) {
|
|
@@ -26,14 +71,18 @@ export async function resolveProvisionerTokenByHash(hashedToken) {
|
|
|
26
71
|
return toProvisionerToken(row);
|
|
27
72
|
}
|
|
28
73
|
export async function revokeProvisionerToken(params) {
|
|
29
|
-
const rows = await db().
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
74
|
+
const rows = await db().transaction(async (tx)=>{
|
|
75
|
+
const rows = await tx.update(provisionerTokens).set({
|
|
76
|
+
revokedAt: new Date(),
|
|
77
|
+
revokedByUserId: params.revokedByUserId,
|
|
78
|
+
updatedAt: new Date()
|
|
79
|
+
}).where(and(eq(provisionerTokens.id, params.tokenId), eq(provisionerTokens.workspaceId, params.workspaceId), eq(provisionerTokens.scope, 'workspace'), isNull(provisionerTokens.revokedAt))).returning();
|
|
80
|
+
if (rows[0]) await cascadeProvisionerRevocation(tx, params.tokenId);
|
|
81
|
+
return rows;
|
|
82
|
+
});
|
|
34
83
|
const row = rows[0];
|
|
35
84
|
if (row) return toProvisionerToken(row);
|
|
36
|
-
const existingRows = await db().select().from(provisionerTokens).where(and(eq(provisionerTokens.id, params.tokenId), eq(provisionerTokens.workspaceId, params.workspaceId))).limit(1);
|
|
85
|
+
const existingRows = await db().select().from(provisionerTokens).where(and(eq(provisionerTokens.id, params.tokenId), eq(provisionerTokens.workspaceId, params.workspaceId), eq(provisionerTokens.scope, 'workspace'))).limit(1);
|
|
37
86
|
const existingRow = existingRows[0];
|
|
38
87
|
if (!existingRow) return undefined;
|
|
39
88
|
return toProvisionerToken(existingRow);
|
|
@@ -45,7 +94,7 @@ export async function touchProvisionerLastSeen(params) {
|
|
|
45
94
|
}).where(and(eq(provisionerTokens.id, params.tokenId), or(isNull(provisionerTokens.lastSeenAt), sql`${provisionerTokens.lastSeenAt} < now() - (${params.throttleSeconds} || ' seconds')::interval`)));
|
|
46
95
|
}
|
|
47
96
|
export async function listActiveProvisionerTokens(params) {
|
|
48
|
-
const rows = await db().select().from(provisionerTokens).where(and(eq(provisionerTokens.workspaceId, params.workspaceId), isNull(provisionerTokens.revokedAt), or(isNull(provisionerTokens.expiresAt), gt(provisionerTokens.expiresAt, sql`now()`)), sql`${provisionerTokens.lastSeenAt} > now() - (${params.windowSeconds} || ' seconds')::interval`)).orderBy(desc(provisionerTokens.lastSeenAt), desc(provisionerTokens.id));
|
|
97
|
+
const rows = await db().select().from(provisionerTokens).where(and(eq(provisionerTokens.workspaceId, params.workspaceId), eq(provisionerTokens.scope, 'workspace'), isNull(provisionerTokens.revokedAt), or(isNull(provisionerTokens.expiresAt), gt(provisionerTokens.expiresAt, sql`now()`)), sql`${provisionerTokens.lastSeenAt} > now() - (${params.windowSeconds} || ' seconds')::interval`)).orderBy(desc(provisionerTokens.lastSeenAt), desc(provisionerTokens.id));
|
|
49
98
|
return rows.map(toProvisionerToken).filter((token)=>{
|
|
50
99
|
return token.lastSeenAt !== null;
|
|
51
100
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/db/provisioner-tokens.ts"],"sourcesContent":["import {and, desc, eq, gt, isNull, or, sql} from 'drizzle-orm';\nimport type {ActiveProvisionerToken, ProvisionerToken} from '#core/entities/provisioner-token.js';\nimport {db} from './db.js';\nimport {provisionerTokens, toProvisionerToken} from './schema/provisioner-tokens.js';\n\nexport interface CreateProvisionerTokenParams {\n workspaceId: string;\n hashedToken: string;\n prefix: string;\n createdByUserId: string;\n name?: string | undefined;\n expiresAt?: Date | undefined;\n}\n\nexport async function createProvisionerToken(\n params: CreateProvisionerTokenParams,\n): Promise<ProvisionerToken> {\n const rows = await db()\n .insert(provisionerTokens)\n .values({\n workspaceId: params.workspaceId,\n hashedToken: params.hashedToken,\n prefix: params.prefix,\n createdByUserId: params.createdByUserId,\n name: params.name ?? null,\n expiresAt: params.expiresAt ?? null,\n })\n .returning();\n\n const row = rows[0];\n if (!row) throw new Error('Insert returned no rows');\n return toProvisionerToken(row);\n}\n\nexport async function listUsableProvisionerTokensByWorkspaceId(\n workspaceId: string,\n): Promise<ProvisionerToken[]> {\n const now = new Date();\n const rows = await db()\n .select()\n .from(provisionerTokens)\n .where(\n and(\n eq(provisionerTokens.workspaceId, workspaceId),\n isNull(provisionerTokens.revokedAt),\n or(isNull(provisionerTokens.expiresAt), gt(provisionerTokens.expiresAt, now)),\n ),\n )\n .orderBy(desc(provisionerTokens.createdAt), desc(provisionerTokens.id));\n\n return rows.map(toProvisionerToken);\n}\n\nexport async function resolveProvisionerTokenByHash(\n hashedToken: string,\n): Promise<ProvisionerToken | undefined> {\n const rows = await db()\n .select()\n .from(provisionerTokens)\n .where(eq(provisionerTokens.hashedToken, hashedToken))\n .limit(1);\n\n const row = rows[0];\n if (!row) return undefined;\n return toProvisionerToken(row);\n}\n\nexport async function revokeProvisionerToken(params: {\n tokenId: string;\n workspaceId: string;\n revokedByUserId: string;\n}): Promise<ProvisionerToken | undefined> {\n const rows = await db()\n .update(provisionerTokens)\n .set({revokedAt: new Date(), revokedByUserId: params.revokedByUserId, updatedAt: new Date()})\n .where(\n and(\n eq(provisionerTokens.id, params.tokenId),\n eq(provisionerTokens.workspaceId, params.workspaceId),\n isNull(provisionerTokens.revokedAt),\n ),\n )\n .returning();\n\n const row = rows[0];\n if (row) return toProvisionerToken(row);\n\n const existingRows = await db()\n .select()\n .from(provisionerTokens)\n .where(\n and(\n eq(provisionerTokens.id, params.tokenId),\n eq(provisionerTokens.workspaceId, params.workspaceId),\n ),\n )\n .limit(1);\n\n const existingRow = existingRows[0];\n if (!existingRow) return undefined;\n return toProvisionerToken(existingRow);\n}\n\nexport async function touchProvisionerLastSeen(params: {\n tokenId: string;\n throttleSeconds: number;\n}): Promise<void> {\n await db()\n .update(provisionerTokens)\n .set({lastSeenAt: sql`now()`, updatedAt: sql`now()`})\n .where(\n and(\n eq(provisionerTokens.id, params.tokenId),\n or(\n isNull(provisionerTokens.lastSeenAt),\n sql`${provisionerTokens.lastSeenAt} < now() - (${params.throttleSeconds} || ' seconds')::interval`,\n ),\n ),\n );\n}\n\nexport async function listActiveProvisionerTokens(params: {\n workspaceId: string;\n windowSeconds: number;\n}): Promise<ActiveProvisionerToken[]> {\n const rows = await db()\n .select()\n .from(provisionerTokens)\n .where(\n and(\n eq(provisionerTokens.workspaceId, params.workspaceId),\n isNull(provisionerTokens.revokedAt),\n or(isNull(provisionerTokens.expiresAt), gt(provisionerTokens.expiresAt, sql`now()`)),\n sql`${provisionerTokens.lastSeenAt} > now() - (${params.windowSeconds} || ' seconds')::interval`,\n ),\n )\n .orderBy(desc(provisionerTokens.lastSeenAt), desc(provisionerTokens.id));\n\n return rows.map(toProvisionerToken).filter((token): token is ActiveProvisionerToken => {\n return token.lastSeenAt !== null;\n });\n}\n"],"names":["and","desc","eq","gt","isNull","or","sql","db","provisionerTokens","toProvisionerToken","createProvisionerToken","params","rows","insert","values","workspaceId","hashedToken","prefix","createdByUserId","name","expiresAt","returning","row","Error","listUsableProvisionerTokensByWorkspaceId","now","Date","select","from","where","revokedAt","orderBy","createdAt","id","map","resolveProvisionerTokenByHash","limit","undefined","revokeProvisionerToken","update","set","revokedByUserId","updatedAt","tokenId","existingRows","existingRow","touchProvisionerLastSeen","lastSeenAt","throttleSeconds","listActiveProvisionerTokens","windowSeconds","filter","token"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/db/provisioner-tokens.ts"],"sourcesContent":["import {and, desc, eq, gt, inArray, isNull, or, sql} from 'drizzle-orm';\nimport type {\n ActiveProvisionerToken,\n ProvisionerScope,\n ProvisionerToken,\n} from '#core/entities/provisioner-token.js';\nimport {db} from './db.js';\nimport {provisionerTokens, toProvisionerToken} from './schema/provisioner-tokens.js';\nimport {runnerActivationTokens} from './schema/runner-activation-tokens.js';\nimport {runnerBootstrapTokens, runnerControlSessions} from './schema/runner-control-sessions.js';\nimport {providerRunners} from './schema/runner-instances.js';\nimport {runnerSessions} from './schema/runner-sessions.js';\n\nexport interface CreateProvisionerTokenParams {\n scope: ProvisionerScope;\n workspaceId?: string | undefined;\n hashedToken: string;\n prefix: string;\n createdByUserId: string;\n name?: string | undefined;\n expiresAt?: Date | undefined;\n}\n\nasync function cascadeProvisionerRevocation(\n tx: Parameters<Parameters<ReturnType<typeof db>['transaction']>[0]>[0],\n provisionerId: string,\n) {\n await tx\n .update(runnerBootstrapTokens)\n .set({revokedAt: sql`now()`})\n .where(eq(runnerBootstrapTokens.provisionerId, provisionerId));\n await tx\n .update(runnerControlSessions)\n .set({closedAt: sql`now()`, closeReason: 'provisioner-revoked'})\n .where(\n and(\n eq(runnerControlSessions.provisionerId, provisionerId),\n isNull(runnerControlSessions.closedAt),\n ),\n );\n await tx\n .update(runnerActivationTokens)\n .set({revokedAt: sql`now()`})\n .where(\n and(\n isNull(runnerActivationTokens.consumedAt),\n isNull(runnerActivationTokens.revokedAt),\n inArray(\n runnerActivationTokens.runnerInstanceId,\n tx\n .select({id: providerRunners.id})\n .from(providerRunners)\n .where(eq(providerRunners.provisionerId, provisionerId)),\n ),\n ),\n );\n await tx\n .update(providerRunners)\n .set({state: 'terminated', terminatedAt: sql`now()`, updatedAt: sql`now()`})\n .where(\n and(\n eq(providerRunners.provisionerId, provisionerId),\n isNull(providerRunners.runnerSessionId),\n ),\n );\n await tx\n .update(runnerSessions)\n .set({revokedAt: sql`now()`})\n .where(\n and(\n eq(runnerSessions.provisionerId, provisionerId),\n eq(runnerSessions.claimsUsed, 0),\n isNull(runnerSessions.revokedAt),\n ),\n );\n}\n\nexport async function createProvisionerToken(\n params: CreateProvisionerTokenParams,\n): Promise<ProvisionerToken> {\n const rows = await db()\n .insert(provisionerTokens)\n .values({\n scope: params.scope,\n workspaceId: params.workspaceId ?? null,\n hashedToken: params.hashedToken,\n prefix: params.prefix,\n createdByUserId: params.createdByUserId,\n name: params.name ?? null,\n expiresAt: params.expiresAt ?? null,\n })\n .returning();\n\n const row = rows[0];\n if (!row) throw new Error('Insert returned no rows');\n return toProvisionerToken(row);\n}\n\nexport async function revokeInstallationProvisionerToken(params: {\n tokenId: string;\n revokedByUserId: string;\n}): Promise<ProvisionerToken | undefined> {\n const rows = await db().transaction(async (tx) => {\n const rows = await tx\n .update(provisionerTokens)\n .set({revokedAt: new Date(), revokedByUserId: params.revokedByUserId, updatedAt: new Date()})\n .where(\n and(\n eq(provisionerTokens.id, params.tokenId),\n eq(provisionerTokens.scope, 'installation'),\n isNull(provisionerTokens.revokedAt),\n ),\n )\n .returning();\n if (rows[0]) {\n await cascadeProvisionerRevocation(tx, params.tokenId);\n }\n return rows;\n });\n\n const row = rows[0];\n if (row) return toProvisionerToken(row);\n\n const existingRows = await db()\n .select()\n .from(provisionerTokens)\n .where(\n and(eq(provisionerTokens.id, params.tokenId), eq(provisionerTokens.scope, 'installation')),\n )\n .limit(1);\n const existingRow = existingRows[0];\n return existingRow ? toProvisionerToken(existingRow) : undefined;\n}\n\nexport async function listUsableProvisionerTokensByWorkspaceId(\n workspaceId: string,\n): Promise<ProvisionerToken[]> {\n const now = new Date();\n const rows = await db()\n .select()\n .from(provisionerTokens)\n .where(\n and(\n eq(provisionerTokens.workspaceId, workspaceId),\n eq(provisionerTokens.scope, 'workspace'),\n isNull(provisionerTokens.revokedAt),\n or(isNull(provisionerTokens.expiresAt), gt(provisionerTokens.expiresAt, now)),\n ),\n )\n .orderBy(desc(provisionerTokens.createdAt), desc(provisionerTokens.id));\n\n return rows.map(toProvisionerToken);\n}\n\nexport async function resolveProvisionerTokenByHash(\n hashedToken: string,\n): Promise<ProvisionerToken | undefined> {\n const rows = await db()\n .select()\n .from(provisionerTokens)\n .where(eq(provisionerTokens.hashedToken, hashedToken))\n .limit(1);\n\n const row = rows[0];\n if (!row) return undefined;\n return toProvisionerToken(row);\n}\n\nexport async function revokeProvisionerToken(params: {\n tokenId: string;\n workspaceId: string;\n revokedByUserId: string;\n}): Promise<ProvisionerToken | undefined> {\n const rows = await db().transaction(async (tx) => {\n const rows = await tx\n .update(provisionerTokens)\n .set({revokedAt: new Date(), revokedByUserId: params.revokedByUserId, updatedAt: new Date()})\n .where(\n and(\n eq(provisionerTokens.id, params.tokenId),\n eq(provisionerTokens.workspaceId, params.workspaceId),\n eq(provisionerTokens.scope, 'workspace'),\n isNull(provisionerTokens.revokedAt),\n ),\n )\n .returning();\n if (rows[0]) await cascadeProvisionerRevocation(tx, params.tokenId);\n return rows;\n });\n\n const row = rows[0];\n if (row) return toProvisionerToken(row);\n\n const existingRows = await db()\n .select()\n .from(provisionerTokens)\n .where(\n and(\n eq(provisionerTokens.id, params.tokenId),\n eq(provisionerTokens.workspaceId, params.workspaceId),\n eq(provisionerTokens.scope, 'workspace'),\n ),\n )\n .limit(1);\n\n const existingRow = existingRows[0];\n if (!existingRow) return undefined;\n return toProvisionerToken(existingRow);\n}\n\nexport async function touchProvisionerLastSeen(params: {\n tokenId: string;\n throttleSeconds: number;\n}): Promise<void> {\n await db()\n .update(provisionerTokens)\n .set({lastSeenAt: sql`now()`, updatedAt: sql`now()`})\n .where(\n and(\n eq(provisionerTokens.id, params.tokenId),\n or(\n isNull(provisionerTokens.lastSeenAt),\n sql`${provisionerTokens.lastSeenAt} < now() - (${params.throttleSeconds} || ' seconds')::interval`,\n ),\n ),\n );\n}\n\nexport async function listActiveProvisionerTokens(params: {\n workspaceId: string;\n windowSeconds: number;\n}): Promise<ActiveProvisionerToken[]> {\n const rows = await db()\n .select()\n .from(provisionerTokens)\n .where(\n and(\n eq(provisionerTokens.workspaceId, params.workspaceId),\n eq(provisionerTokens.scope, 'workspace'),\n isNull(provisionerTokens.revokedAt),\n or(isNull(provisionerTokens.expiresAt), gt(provisionerTokens.expiresAt, sql`now()`)),\n sql`${provisionerTokens.lastSeenAt} > now() - (${params.windowSeconds} || ' seconds')::interval`,\n ),\n )\n .orderBy(desc(provisionerTokens.lastSeenAt), desc(provisionerTokens.id));\n\n return rows.map(toProvisionerToken).filter((token): token is ActiveProvisionerToken => {\n return token.lastSeenAt !== null;\n });\n}\n"],"names":["and","desc","eq","gt","inArray","isNull","or","sql","db","provisionerTokens","toProvisionerToken","runnerActivationTokens","runnerBootstrapTokens","runnerControlSessions","providerRunners","runnerSessions","cascadeProvisionerRevocation","tx","provisionerId","update","set","revokedAt","where","closedAt","closeReason","consumedAt","runnerInstanceId","select","id","from","state","terminatedAt","updatedAt","runnerSessionId","claimsUsed","createProvisionerToken","params","rows","insert","values","scope","workspaceId","hashedToken","prefix","createdByUserId","name","expiresAt","returning","row","Error","revokeInstallationProvisionerToken","transaction","Date","revokedByUserId","tokenId","existingRows","limit","existingRow","undefined","listUsableProvisionerTokensByWorkspaceId","now","orderBy","createdAt","map","resolveProvisionerTokenByHash","revokeProvisionerToken","touchProvisionerLastSeen","lastSeenAt","throttleSeconds","listActiveProvisionerTokens","windowSeconds","filter","token"],"mappings":"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"}
|
|
@@ -7,6 +7,7 @@ export interface ReservationTemplate {
|
|
|
7
7
|
running: number;
|
|
8
8
|
}
|
|
9
9
|
export interface DemandStat {
|
|
10
|
+
workspaceId?: string;
|
|
10
11
|
labels: string[];
|
|
11
12
|
queued: number;
|
|
12
13
|
reserved: number;
|
|
@@ -14,6 +15,7 @@ export interface DemandStat {
|
|
|
14
15
|
}
|
|
15
16
|
export interface ReservationGrant {
|
|
16
17
|
reservationId: string;
|
|
18
|
+
workspaceId?: string;
|
|
17
19
|
labels: string[];
|
|
18
20
|
count: number;
|
|
19
21
|
expiresAt: Date;
|
|
@@ -24,6 +26,17 @@ export interface PollDemandAndReserveParams {
|
|
|
24
26
|
maxReservations: number;
|
|
25
27
|
ttlSeconds: number;
|
|
26
28
|
templates: ReservationTemplate[];
|
|
29
|
+
capabilityWindowSeconds?: number;
|
|
30
|
+
}
|
|
31
|
+
export interface InstallationPollDemandAndReserveParams {
|
|
32
|
+
provisionerId: string;
|
|
33
|
+
maxReservations: number;
|
|
34
|
+
ttlSeconds: number;
|
|
35
|
+
templates: ReservationTemplate[];
|
|
36
|
+
capabilityWindowSeconds: number;
|
|
37
|
+
eligibleWorkspaceIds: ReadonlySet<string>;
|
|
38
|
+
signal?: AbortSignal;
|
|
39
|
+
onReservations?: (reservations: ReservationGrant[]) => void;
|
|
27
40
|
}
|
|
28
41
|
export declare function pollDemandAndReserve(params: PollDemandAndReserveParams): Promise<{
|
|
29
42
|
stats: DemandStat[];
|
|
@@ -33,6 +46,11 @@ export declare function pollDemandAndReserveTx(tx: Tx, params: PollDemandAndRese
|
|
|
33
46
|
stats: DemandStat[];
|
|
34
47
|
reservations: ReservationGrant[];
|
|
35
48
|
}>;
|
|
49
|
+
export declare function pollInstallationDemandAndReserve(params: InstallationPollDemandAndReserveParams): Promise<{
|
|
50
|
+
stats: DemandStat[];
|
|
51
|
+
reservations: ReservationGrant[];
|
|
52
|
+
}>;
|
|
53
|
+
export declare function listQueuedDemandWorkspaceIds(): Promise<string[]>;
|
|
36
54
|
export declare function deleteExpiredReservations(params?: {
|
|
37
55
|
limit?: number;
|
|
38
56
|
}): Promise<number>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reservations.d.ts","sourceRoot":"","sources":["../../src/db/reservations.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,EAAE,EAAC,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"reservations.d.ts","sourceRoot":"","sources":["../../src/db/reservations.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,EAAE,EAAC,MAAM,SAAS,CAAC;AAOhC,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,IAAI,CAAC;CACtB;AAED,MAAM,WAAW,gBAAgB;IAC/B,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,0BAA0B;IACzC,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,mBAAmB,EAAE,CAAC;IACjC,uBAAuB,CAAC,EAAE,MAAM,CAAC;CAClC;AAED,MAAM,WAAW,sCAAsC;IACrD,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,mBAAmB,EAAE,CAAC;IACjC,uBAAuB,EAAE,MAAM,CAAC;IAChC,oBAAoB,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC1C,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,cAAc,CAAC,EAAE,CAAC,YAAY,EAAE,gBAAgB,EAAE,KAAK,IAAI,CAAC;CAC7D;AAcD,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,0BAA0B,GACjC,OAAO,CAAC;IAAC,KAAK,EAAE,UAAU,EAAE,CAAC;IAAC,YAAY,EAAE,gBAAgB,EAAE,CAAA;CAAC,CAAC,CAIlE;AAED,wBAAsB,sBAAsB,CAC1C,EAAE,EAAE,EAAE,EACN,MAAM,EAAE,0BAA0B,GACjC,OAAO,CAAC;IAAC,KAAK,EAAE,UAAU,EAAE,CAAC;IAAC,YAAY,EAAE,gBAAgB,EAAE,CAAA;CAAC,CAAC,CAGlE;AAED,wBAAsB,gCAAgC,CACpD,MAAM,EAAE,sCAAsC,GAC7C,OAAO,CAAC;IAAC,KAAK,EAAE,UAAU,EAAE,CAAC;IAAC,YAAY,EAAE,gBAAgB,EAAE,CAAA;CAAC,CAAC,CA2ClE;AA8JD,wBAAsB,4BAA4B,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAMtE;AA0BD,wBAAsB,yBAAyB,CAAC,MAAM,CAAC,EAAE;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAc1F;AAED,wBAAsB,uBAAuB,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAS5E;AAED,wBAAsB,uBAAuB,CAC3C,EAAE,EAAE,EAAE,EACN,MAAM,EAAE;IACN,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,KAAK,CAAC;QAAC,aAAa,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAC,CAAC,CAAC;CACzD,GACA,OAAO,CAAC,MAAM,CAAC,CA0CjB"}
|