@nosana/node 1.1.44-rc → 1.1.45-rc

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.44-rc",
3
+ "version": "1.1.45-rc",
4
4
  "description": "",
5
5
  "bin": {
6
6
  "nosana-node": "./dist/src/index.js"
@@ -392,6 +392,14 @@ export async function runTaskManagerOperation(flow, op, dependent) {
392
392
  }
393
393
  // Loop through each operation that depends on this one
394
394
  for (const id of dependent) {
395
+ // A dependency can report itself up more than once, and only an operation
396
+ // that has not started yet may be released.
397
+ const status = this.operationStatus.get(id);
398
+ if (status !== OperationProgressStatuses.PENDING &&
399
+ status !== OperationProgressStatuses.WAITING &&
400
+ status !== OperationProgressStatuses.INIT) {
401
+ continue;
402
+ }
395
403
  const dependencyContext = this.dependecyMap.get(id);
396
404
  // Schedule the dependent operation to start, now that its dependency is healthy
397
405
  this.currentGroupOperationsPromises.set(id, this.trackGroupOperationPromise(id, this.setUpOperationFunc(flow, id, dependencyContext.dependents)));
@@ -14,6 +14,9 @@ export declare class ExposedPortHealthCheck {
14
14
  private healthStatus;
15
15
  private jobEmitter;
16
16
  private intervals;
17
+ private readonly connectTimeoutSeconds;
18
+ private readonly startupMaxTimeSeconds;
19
+ private readonly continuousMaxTimeSeconds;
17
20
  private flowId;
18
21
  constructor(flowId: string, frpcContainer: Dockerode.Container, jobEmitter: EventEmitter, containerName: string, startupIntervalMs?: number, continuousIntervalMs?: number);
19
22
  addExposedPortsMap(exposedPortMap: Map<string, ExposedPort>): void;
@@ -6,6 +6,14 @@ export class ExposedPortHealthCheck {
6
6
  */
7
7
  this.healthStatus = new Map();
8
8
  this.intervals = new Map();
9
+ // Every curl is bounded: an unbounded one holds the startup check open and
10
+ // nothing waiting on the service ever starts. The startup budget is generous
11
+ // because a health check can be a real request against a model that is still
12
+ // loading, and checks there never overlap. The continuous budget stays under
13
+ // the interval it runs on, where nothing serialises them.
14
+ this.connectTimeoutSeconds = 2;
15
+ this.startupMaxTimeSeconds = 60;
16
+ this.continuousMaxTimeSeconds = 20;
9
17
  this.flowId = flowId;
10
18
  this.frpcContainer = frpcContainer;
11
19
  this.jobEmitter = jobEmitter;
@@ -23,8 +31,15 @@ export class ExposedPortHealthCheck {
23
31
  }
24
32
  startStartupHealthCheck(id, exposedPort) {
25
33
  let startupCheckInterval = null;
34
+ let checkInFlight = false;
26
35
  startupCheckInterval = setInterval(async () => {
27
- const success = await this.checkPortHealth(exposedPort, true);
36
+ // Two checks in flight both report the service up.
37
+ if (checkInFlight)
38
+ return;
39
+ checkInFlight = true;
40
+ const success = await this.checkPortHealth(exposedPort, true).finally(() => {
41
+ checkInFlight = false;
42
+ });
28
43
  if (success == null) {
29
44
  clearInterval(startupCheckInterval);
30
45
  this.jobEmitter.emit('healthcheck:url:exposed', {
@@ -92,29 +107,36 @@ export class ExposedPortHealthCheck {
92
107
  if (!exposedPort.health_checks || exposedPort.health_checks.length === 0) {
93
108
  return null; // Return null to indicate no check was done.
94
109
  }
110
+ const maxTimeSeconds = initialRun
111
+ ? this.startupMaxTimeSeconds
112
+ : this.continuousMaxTimeSeconds;
95
113
  for (const healthCheck of exposedPort.health_checks) {
96
114
  if (!initialRun && !healthCheck.continuous) {
97
115
  return null;
98
116
  }
99
117
  if (healthCheck.type === 'http' && typeof exposedPort.port === 'number') {
100
- const success = await this.runHttpHealthCheck(exposedPort.port, healthCheck);
118
+ const success = await this.runHttpHealthCheck(exposedPort.port, healthCheck, maxTimeSeconds);
101
119
  if (!success)
102
120
  return false;
103
121
  }
104
122
  else if (healthCheck.type === 'websocket' &&
105
123
  typeof exposedPort.port === 'number') {
106
- const success = await this.runWebSocketHealthCheck(exposedPort.port, healthCheck);
124
+ const success = await this.runWebSocketHealthCheck(exposedPort.port, healthCheck, maxTimeSeconds);
107
125
  if (!success)
108
126
  return false;
109
127
  }
110
128
  }
111
129
  return true;
112
130
  }
113
- async runHttpHealthCheck(port, healthCheck) {
131
+ async runHttpHealthCheck(port, healthCheck, maxTimeSeconds) {
114
132
  const url = `http://${this.containerName}:${port}${healthCheck.path}`;
115
133
  const cmd = [
116
134
  'curl',
117
135
  '-s',
136
+ '--connect-timeout',
137
+ String(this.connectTimeoutSeconds),
138
+ '--max-time',
139
+ String(maxTimeSeconds),
118
140
  '-o',
119
141
  '/dev/null',
120
142
  '-w',
@@ -145,8 +167,17 @@ export class ExposedPortHealthCheck {
145
167
  return false;
146
168
  }
147
169
  }
148
- async runWebSocketHealthCheck(port, healthCheck) {
149
- const cmd = ['curl', '--include', '--no-buffer', `ws://localhost:${port}`];
170
+ async runWebSocketHealthCheck(port, healthCheck, maxTimeSeconds) {
171
+ const cmd = [
172
+ 'curl',
173
+ '--include',
174
+ '--no-buffer',
175
+ '--connect-timeout',
176
+ String(this.connectTimeoutSeconds),
177
+ '--max-time',
178
+ String(maxTimeSeconds),
179
+ `ws://localhost:${port}`,
180
+ ];
150
181
  try {
151
182
  const output = await this.execCommand(cmd);
152
183
  return output.includes(healthCheck.expected_response);
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@nosana/node",
3
- "version": "1.1.44-rc",
3
+ "version": "1.1.45-rc",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@nosana/node",
9
- "version": "1.1.44-rc",
9
+ "version": "1.1.45-rc",
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.44-rc",
3
+ "version": "1.1.45-rc",
4
4
  "description": "",
5
5
  "bin": {
6
6
  "nosana-node": "./dist/src/index.js"