@shipfox/api-runners 7.0.2 → 7.1.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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@shipfox/api-runners",
3
3
  "license": "MIT",
4
- "version": "7.0.2",
4
+ "version": "7.1.0",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "git+https://github.com/ShipfoxHQ/shipfox.git",
@@ -25,21 +25,22 @@
25
25
  "@temporalio/workflow": "1.18.1",
26
26
  "drizzle-orm": "^0.45.2",
27
27
  "zod": "^4.4.3",
28
- "@shipfox/api-auth-context": "6.0.0",
29
- "@shipfox/api-auth-dto": "6.0.0",
28
+ "@shipfox/api-auth-context": "7.1.0",
29
+ "@shipfox/api-auth-dto": "7.1.0",
30
30
  "@shipfox/api-runners-dto": "7.0.1",
31
31
  "@shipfox/api-workflows-dto": "6.0.0",
32
32
  "@shipfox/config": "1.2.2",
33
33
  "@shipfox/inter-module": "0.2.0",
34
34
  "@shipfox/node-drizzle": "0.3.2",
35
+ "@shipfox/node-error-monitoring": "0.2.0",
35
36
  "@shipfox/node-auth-root-key": "0.2.1",
36
- "@shipfox/node-fastify": "0.2.4",
37
- "@shipfox/node-module": "0.4.0",
38
- "@shipfox/node-opentelemetry": "0.5.2",
37
+ "@shipfox/node-fastify": "0.3.0",
38
+ "@shipfox/node-module": "0.5.0",
39
+ "@shipfox/node-opentelemetry": "0.6.0",
39
40
  "@shipfox/node-outbox": "0.2.4",
40
41
  "@shipfox/node-postgres": "0.4.2",
41
42
  "@shipfox/node-rate-limit": "0.3.0",
42
- "@shipfox/node-temporal": "0.3.2",
43
+ "@shipfox/node-temporal": "0.4.0",
43
44
  "@shipfox/node-tokens": "0.3.0",
44
45
  "@shipfox/runner-labels": "0.1.1"
45
46
  },
@@ -1822,6 +1822,53 @@ describe('reconcileRunnerInstances', () => {
1822
1822
  });
1823
1823
 
1824
1824
  describe('runner instance provider attachment', () => {
1825
+ it('updates the pre-created runner instance before its first lifecycle report', async () => {
1826
+ const provisionerId = crypto.randomUUID();
1827
+ const providerRunnerId = 'ec2-runner-1';
1828
+ const [instance] = await db()
1829
+ .insert(providerRunners)
1830
+ .values({
1831
+ provisionerId,
1832
+ providerKind: 'ec2',
1833
+ templateKey: 'linux',
1834
+ labels: ['linux'],
1835
+ state: 'starting',
1836
+ reportedAt: new Date(),
1837
+ })
1838
+ .returning({id: providerRunners.id});
1839
+ if (!instance) throw new Error('Runner instance insert returned no row');
1840
+
1841
+ const attached = await attachRunnerInstanceProviderId({
1842
+ runnerInstanceId: instance.id,
1843
+ provisionerId,
1844
+ providerRunnerId,
1845
+ });
1846
+ await reportRunnerInstances({
1847
+ workspaceId: null,
1848
+ provisionerId,
1849
+ events: [
1850
+ {
1851
+ providerRunnerId,
1852
+ reservationId: null,
1853
+ templateKey: 'linux',
1854
+ labels: ['linux'],
1855
+ state: 'starting',
1856
+ reason: null,
1857
+ runnerSessionId: null,
1858
+ providerKind: 'ec2',
1859
+ reportedAt: new Date(),
1860
+ },
1861
+ ],
1862
+ });
1863
+ const rows = await db()
1864
+ .select()
1865
+ .from(providerRunners)
1866
+ .where(eq(providerRunners.provisionerId, provisionerId));
1867
+
1868
+ expect(attached).toBe(true);
1869
+ expect(rows).toMatchObject([{id: instance.id, providerRunnerId, state: 'starting'}]);
1870
+ });
1871
+
1825
1872
  it('belongs to its provisioner until it receives one provider runner identity', async () => {
1826
1873
  const provisionerId = crypto.randomUUID();
1827
1874
  const [instance] = await db()
@@ -4,7 +4,9 @@ import {
4
4
  } from '@shipfox/api-auth-context';
5
5
  import type {PollDemandTemplateDto} from '@shipfox/api-runners-dto';
6
6
  import {pollDemandBodySchema, pollDemandResponseSchema} from '@shipfox/api-runners-dto';
7
+ import {reportError} from '@shipfox/node-error-monitoring';
7
8
  import {ClientError, defineRoute} from '@shipfox/node-fastify';
9
+ import {logger} from '@shipfox/node-opentelemetry';
8
10
  import {config} from '#config.js';
9
11
  import {pollDemand, releaseReservationGrants} from '#core/demand.js';
10
12
  import {publishWorkspaceProvisionerCapabilitySnapshot} from '#db/provisioner-capability-snapshots.js';
@@ -50,7 +52,17 @@ export function createPollDemandRoute(options: CreateRunnersModuleOptions = {})
50
52
  reply.raw.on('close', () => {
51
53
  if (!responseFinished) {
52
54
  abortController.abort();
53
- void releaseReservationGrants(responseReservations).catch(() => undefined);
55
+ void releaseReservationGrants(responseReservations).catch((error) => {
56
+ logger().error(
57
+ {err: error, reservationCount: responseReservations.length},
58
+ 'Failed to release reservations after provisioner disconnect',
59
+ );
60
+ reportError(error, {
61
+ boundary: 'runners.cleanup',
62
+ operation: 'release-disconnected-reservations',
63
+ extra: {reservationCount: responseReservations.length},
64
+ });
65
+ });
54
66
  }
55
67
  });
56
68
  const provisionerContext = requireProvisionerContext(request);