@nosana/node 1.1.59 → 1.1.61-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 +1 -1
- package/dist/src/NodeManager/node/api/routes/wss/log.d.ts +1 -1
- package/dist/src/NodeManager/node/api/routes/wss/log.js +15 -3
- package/dist/src/NodeManager/node/job/jobExternalUtil.js +4 -2
- package/dist/src/NodeManager/utils/timeoutPromiseWrapper.js +9 -2
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
package/dist/package.json
CHANGED
|
@@ -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
|
|
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
|
-
|
|
16
|
+
const retryDelay = JOB_DEFINITION_RETRY_DELAYS_SECONDS[attempts];
|
|
17
|
+
if (retryDelay === undefined) {
|
|
16
18
|
throw error;
|
|
17
19
|
}
|
|
18
|
-
await sleep(
|
|
20
|
+
await sleep(retryDelay);
|
|
19
21
|
return this.retrieveJobDefinitionWithRetry(ipfsHash, attempts + 1);
|
|
20
22
|
}
|
|
21
23
|
}
|
|
@@ -1,7 +1,14 @@
|
|
|
1
|
+
// Neither the timeout nor a rejected promise can confirm how the wrapped work
|
|
2
|
+
// ended, so both abort as a failure. 'quit' is StopReasons.QUIT, spelled out
|
|
3
|
+
// here to keep this utility off TaskManager's import graph.
|
|
4
|
+
const ABORT_REASON = 'quit';
|
|
1
5
|
export function promiseTimeoutWrapper(promise, expiry_time, abortController) {
|
|
2
6
|
const timeoutError = new Error('Promise took too long to settle, expiry timeout met.');
|
|
7
|
+
// The caller's controller is an operation's own, and its abort reason is read
|
|
8
|
+
// back as a StopReason. A bare abort() would set the reason to a DOMException,
|
|
9
|
+
// which resolves to no status at all.
|
|
3
10
|
const timer = setTimeout(() => {
|
|
4
|
-
abortController.abort();
|
|
11
|
+
abortController.abort(ABORT_REASON);
|
|
5
12
|
}, expiry_time * 1000);
|
|
6
13
|
if (abortController.signal.aborted) {
|
|
7
14
|
return Promise.reject(timeoutError);
|
|
@@ -19,7 +26,7 @@ export function promiseTimeoutWrapper(promise, expiry_time, abortController) {
|
|
|
19
26
|
promise
|
|
20
27
|
.then((value) => resolve(value))
|
|
21
28
|
.catch((error) => {
|
|
22
|
-
abortController.abort();
|
|
29
|
+
abortController.abort(ABORT_REASON);
|
|
23
30
|
reject(error);
|
|
24
31
|
})
|
|
25
32
|
.finally(onSettled);
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nosana/node",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.61-rc",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@nosana/node",
|
|
9
|
-
"version": "1.1.
|
|
9
|
+
"version": "1.1.61-rc",
|
|
10
10
|
"license": "ISC",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@coral-xyz/anchor": "^0.28.1-beta.1",
|