@nosana/node 1.1.60-rc → 1.1.62-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.60-rc",
3
+ "version": "1.1.62-rc",
4
4
  "description": "",
5
5
  "bin": {
6
6
  "nosana-node": "./dist/src/index.js"
@@ -11,4 +11,4 @@ export declare function wssTaskManagerLogRoute(ws: WebSocket, _: string, { jobAd
11
11
  group?: string;
12
12
  opId?: string;
13
13
  type?: string;
14
- }): void;
14
+ }): Promise<void>;
@@ -1,3 +1,4 @@
1
+ import WebSocket from 'ws';
1
2
  import { logStreaming } from '../../../../monitoring/streaming/LogStreamer.js';
2
3
  import { getSDK } from '../../../../sdk/index.js';
3
4
  import { TaskManagerRegistry } from '../../../task/TaskManagerRegistry.js';
@@ -10,8 +11,17 @@ export async function wssLogRoute(ws, _, { jobAddress }) {
10
11
  const walletAddress = sdk.solana.wallet.toString();
11
12
  logStreaming(walletAddress).subscribe(ws, jobAddress);
12
13
  }
13
- export function wssTaskManagerLogRoute(ws, _, { jobAddress, group, opId, type, }) {
14
- const task = TaskManagerRegistry.getInstance().get(jobAddress);
14
+ export async function wssTaskManagerLogRoute(ws, _, { jobAddress, group, opId, type, }) {
15
+ const registry = TaskManagerRegistry.getInstance();
16
+ const deadline = Date.now() + 30000;
17
+ let task = registry.get(jobAddress);
18
+ // A run is visible on-chain before the node has finished loading the job
19
+ // definition and registering its TaskManager. Keep the authenticated socket
20
+ // open during that short startup window instead of forcing clients to race it.
21
+ while (!task && Date.now() < deadline && ws.readyState === WebSocket.OPEN) {
22
+ await new Promise((resolve) => setTimeout(resolve, 250));
23
+ task = registry.get(jobAddress);
24
+ }
15
25
  if (!task)
16
26
  return ws.close(1008, 'Invalid job address');
17
27
  task.subscribe(ws, (log) => {
@@ -29,6 +39,8 @@ export function wssTaskManagerLogRoute(ws, _, { jobAddress, group, opId, type, }
29
39
  try {
30
40
  ws.send(JSON.stringify({ path: 'flog', data: JSON.stringify(log) }));
31
41
  }
32
- catch { }
42
+ catch {
43
+ // The client may disconnect while historical logs are being replayed.
44
+ }
33
45
  }
34
46
  }
@@ -3,6 +3,7 @@ import { IpfsClientSingleton } from '../../../ipfs/IpfsClient.js';
3
3
  import { JobDefinitionStrategySelector } from './defination/JobDefinitionStrategy.js';
4
4
  import { ResultReturnStrategySelector } from './result/ResultReturnStrategy.js';
5
5
  import { createInitialFlow } from '../task/helpers/createInitialFlow.js';
6
+ const JOB_DEFINITION_RETRY_DELAYS_SECONDS = [0.5, 1, 18.5];
6
7
  export class JobExternalUtil {
7
8
  constructor(repository) {
8
9
  this.repository = repository;
@@ -12,10 +13,11 @@ export class JobExternalUtil {
12
13
  return await IpfsClientSingleton.retrieve(ipfsHash);
13
14
  }
14
15
  catch (error) {
15
- if (attempts >= 2) {
16
+ const retryDelay = JOB_DEFINITION_RETRY_DELAYS_SECONDS[attempts];
17
+ if (retryDelay === undefined) {
16
18
  throw error;
17
19
  }
18
- await sleep(10);
20
+ await sleep(retryDelay);
19
21
  return this.retrieveJobDefinitionWithRetry(ipfsHash, attempts + 1);
20
22
  }
21
23
  }
@@ -52,8 +52,10 @@ export const generateProxies = (flowId, op, opIndex, ports, name, operationId, d
52
52
  for (let exposedPort of ports) {
53
53
  // TODO: use ids generated in the taskmanager to make secerts
54
54
  const generatedId = generateExposeId(flowId, opIndex, exposedPort.port, op.args.private);
55
+ // When an op exposes more than one port, include the port in the id so each
56
+ // port gets a distinct deployment endpoint instead of colliding on a shared one.
55
57
  const generatedDeploymentId = deploymentId
56
- ? generateExposeId(deploymentId, op.id, 0, false)
58
+ ? generateExposeId(deploymentId, op.id, ports.length > 1 ? exposedPort.port : 0, false)
57
59
  : undefined;
58
60
  let proxyHTTPHealthCheckPath = undefined;
59
61
  if (exposedPort.health_checks && exposedPort.health_checks.length > 0) {
@@ -1,5 +1,5 @@
1
1
  import { Table } from 'console-table-printer';
2
- import { isOperator, isSpreadMarker, } from '@nosana/sdk';
2
+ import { getExposePorts, isOperator, isSpreadMarker, } from '@nosana/sdk';
3
3
  import { generateExposeId } from '../../../NodeManager/utils/expose-util.js';
4
4
  import { configs } from '../../../NodeManager/configs/configs.js';
5
5
  export function generateDeploymentEndpointsTable(jobDefinition) {
@@ -14,9 +14,12 @@ export function generateDeploymentEndpointsTable(jobDefinition) {
14
14
  if (op.type === 'container/run') {
15
15
  const { expose } = op.args;
16
16
  if (expose) {
17
+ // Mirror generateProxies: only single-port ops fall back to 0, so a
18
+ // multi-port op gets a distinct endpoint per port.
19
+ const exposedPortCount = getExposePorts(op).length;
17
20
  if (typeof expose === 'number' ||
18
21
  (typeof expose === 'string' && !isOperator(expose))) {
19
- const generatedId = generateExposeId(jobDefinition.deployment_id, op.id, 0, false);
22
+ const generatedId = generateExposeId(jobDefinition.deployment_id, op.id, exposedPortCount > 1 ? expose : 0, false);
20
23
  table.addRow({
21
24
  OpId: op.id,
22
25
  Port: expose,
@@ -30,7 +33,7 @@ export function generateDeploymentEndpointsTable(jobDefinition) {
30
33
  if (typeof port === 'string' && isOperator(port))
31
34
  return; // skip dynamic
32
35
  const p = typeof port === 'object' ? port.port : port;
33
- const generatedId = generateExposeId(jobDefinition.deployment_id, op.id, 0, false);
36
+ const generatedId = generateExposeId(jobDefinition.deployment_id, op.id, exposedPortCount > 1 ? p : 0, false);
34
37
  table.addRow({
35
38
  OpId: op.id,
36
39
  Port: p,
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@nosana/node",
3
- "version": "1.1.60-rc",
3
+ "version": "1.1.62-rc",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@nosana/node",
9
- "version": "1.1.60-rc",
9
+ "version": "1.1.62-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.60-rc",
3
+ "version": "1.1.62-rc",
4
4
  "description": "",
5
5
  "bin": {
6
6
  "nosana-node": "./dist/src/index.js"