@nosana/node 1.1.21 → 1.1.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nosana/node",
3
- "version": "1.1.21",
3
+ "version": "1.1.22",
4
4
  "description": "",
5
5
  "bin": {
6
6
  "nosana-node": "./dist/src/index.js"
@@ -3,13 +3,14 @@ import type { EventEmitter } from 'events';
3
3
  /**
4
4
  * Enforces a maximum running time for a single operation.
5
5
  *
6
- * The clock starts when the operation emits `start` (i.e. the container is
7
- * actually running) — the same lifecycle point the rest of
8
- * `runTaskManagerOperation` keys its timeout enforcement off. If the operation
9
- * is still running `timeoutSeconds` later, `onTimeout` is invoked; callers use
10
- * this to abort the op. The timer is cleared as soon as the operation settles
11
- * (`exit`/`error`) or is torn down (`end`), so a normally completing op never
12
- * triggers it.
6
+ * The clock starts on `container:started` — emitted once the container is
7
+ * actually running, i.e. *after* the image pull — so download time is not
8
+ * counted against the operation's allotted run time. (The earlier `start`
9
+ * event, which the provider emits before pulling, is deliberately not used.)
10
+ * If the operation is still running `timeoutSeconds` later, `onTimeout` is
11
+ * invoked; callers use this to abort the op. The timer is cleared as soon as
12
+ * the operation settles (`exit`/`error`) or is torn down (`end`), so a normally
13
+ * completing op never triggers it.
13
14
  *
14
15
  * The unit is seconds, matching the on-chain `job.timeout` convention.
15
16
  *
@@ -1,13 +1,14 @@
1
1
  /**
2
2
  * Enforces a maximum running time for a single operation.
3
3
  *
4
- * The clock starts when the operation emits `start` (i.e. the container is
5
- * actually running) — the same lifecycle point the rest of
6
- * `runTaskManagerOperation` keys its timeout enforcement off. If the operation
7
- * is still running `timeoutSeconds` later, `onTimeout` is invoked; callers use
8
- * this to abort the op. The timer is cleared as soon as the operation settles
9
- * (`exit`/`error`) or is torn down (`end`), so a normally completing op never
10
- * triggers it.
4
+ * The clock starts on `container:started` — emitted once the container is
5
+ * actually running, i.e. *after* the image pull — so download time is not
6
+ * counted against the operation's allotted run time. (The earlier `start`
7
+ * event, which the provider emits before pulling, is deliberately not used.)
8
+ * If the operation is still running `timeoutSeconds` later, `onTimeout` is
9
+ * invoked; callers use this to abort the op. The timer is cleared as soon as
10
+ * the operation settles (`exit`/`error`) or is torn down (`end`), so a normally
11
+ * completing op never triggers it.
11
12
  *
12
13
  * The unit is seconds, matching the on-chain `job.timeout` convention.
13
14
  *
@@ -23,7 +24,8 @@ export function enforceOperationTimeout(emitter, timeoutSeconds, onTimeout) {
23
24
  handle = undefined;
24
25
  }
25
26
  };
26
- emitter.on('start', () => {
27
+ emitter.on('container:started', () => {
28
+ // Defensive: clear first so an unexpected duplicate can't stack timers.
27
29
  clear();
28
30
  handle = setTimeout(() => {
29
31
  handle = undefined;
@@ -73,7 +73,8 @@ export async function runTaskManagerOperation(flow, op, dependent) {
73
73
  this.abortControllerMap.set(op.id, abort);
74
74
  /**
75
75
  * Enforce the operation's maximum run time, if one was supplied on its
76
- * execution. The clock starts when the op emits `start`; if it's still
76
+ * execution. The clock starts when the container is running (`container:started`,
77
+ * i.e. after the image pull), so download time isn't counted. If it's still
77
78
  * running when the timeout elapses, we abort it with EXPIRED — the same
78
79
  * clean (non-failure) stop used for job-level expiry — and record the reason
79
80
  * for diagnostics/auditing.
@@ -137,6 +137,9 @@ export class Provider {
137
137
  if (exist && !exited && container.id) {
138
138
  stateManager = new ContainerStateManager(container, controller, emitter, op.args.restart_policy);
139
139
  await stateManager.startMonitoring();
140
+ // Reused container is already running (no pull needed) — start the
141
+ // op-execution timeout clock here too.
142
+ emitter.emit('container:started');
140
143
  }
141
144
  else {
142
145
  await this.containerOrchestration.pullImage(op.args.image, op.args.authentication?.docker, controller);
@@ -243,6 +246,10 @@ export class Provider {
243
246
  }
244
247
  }
245
248
  container = await this.containerOrchestration.runFlowContainer(op.args.image ?? flow.jobDefinition.global?.image, createContainerOptions);
249
+ // The container is now running (image pull is already done). This is the
250
+ // point the op-execution timeout clock starts from, so pull time isn't
251
+ // counted against it.
252
+ emitter.emit('container:started');
246
253
  const info = await container.inspect();
247
254
  emitter.emit('updateOpState', { providerId: container.id });
248
255
  if (!op.args.trusted_execution_env && info.NetworkSettings?.Networks["NOSANA_GATEWAY"].IPAddress) {
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@nosana/node",
3
- "version": "1.1.21",
3
+ "version": "1.1.22",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@nosana/node",
9
- "version": "1.1.21",
9
+ "version": "1.1.22",
10
10
  "license": "ISC",
11
11
  "dependencies": {
12
12
  "@coral-xyz/anchor": "^0.28.1-beta.1",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nosana/node",
3
- "version": "1.1.21",
3
+ "version": "1.1.22",
4
4
  "description": "",
5
5
  "bin": {
6
6
  "nosana-node": "./dist/src/index.js"