diff --git a/.github/actions/prepare-tests/action.yml b/.github/actions/prepare-tests/action.yml
index 76d700a05..22a38f172 100644
--- a/.github/actions/prepare-tests/action.yml
+++ b/.github/actions/prepare-tests/action.yml
@@ -51,7 +51,7 @@ runs:
shell: bash
run: |
echo "Going to build the SDK on the requestor"
- docker exec -t docker-requestor-1 /bin/sh -c "cd /golem-js && npm i && npm run build"
+ docker exec -t docker-requestor-1 /bin/sh -c "cd /golem-js && npm i --no-progress && npm run build"
echo "Successfully built the SDK on the requestor"
- name: Install Cypress
@@ -59,3 +59,18 @@ runs:
shell: bash
run: |
docker exec -t docker-requestor-1 /bin/sh -c "cd /golem-js && ./node_modules/.bin/cypress install"
+
+ - name: Run a preliminary scan of offers
+ shell: bash
+ run: |
+ docker exec -t docker-requestor-1 /bin/sh -c "npm install --no-progress -g @prekucki/wait-for-n && wait-for-n --limit=6 --appkey=try_golem --subnet=$YAGNA_SUBNET"
+
+ - name: List down sessions seen on that requestor
+ shell: bash
+ run: |
+ docker exec docker-requestor-1 /bin/sh -c "yagna net sessions"
+
+ - name: Run a secondary scan of offers
+ shell: bash
+ run: |
+ docker exec -t docker-requestor-1 /bin/sh -c "npx --no-progress --yes @golem-sdk/cli market scan -k try_golem --subnet-tag $YAGNA_SUBNET --payment-network $PAYMENT_NETWORK"
diff --git a/examples/experimental/express/server.ts b/examples/experimental/express/server.ts
index 2a970081a..83ecdf502 100644
--- a/examples/experimental/express/server.ts
+++ b/examples/experimental/express/server.ts
@@ -1,14 +1,18 @@
import express from "express";
import { JobManager, JobState } from "@golem-sdk/golem-js/experimental";
+import { fileURLToPath } from "url";
const app = express();
const port = 3000;
+// get the absolute path to the public directory in case this file is run from a different directory
+const publicDirectoryPath = fileURLToPath(new URL("./public", import.meta.url));
+
app.use(express.text());
-const golemClient = new JobManager();
+const jobManager = new JobManager();
-await golemClient
+await jobManager
.init()
.then(() => {
console.log("Connected to the Golem Network!");
@@ -23,19 +27,17 @@ app.post("/tts", async (req, res) => {
res.status(400).send("Missing text parameter");
return;
}
- const job = golemClient.createJob({
+ const job = jobManager.createJob({
demand: {
- activity: {
- imageTag: "severyn/espeak:latest",
- },
+ workload: { imageTag: "severyn/espeak:latest" },
},
market: {
rentHours: 0.5,
pricing: {
model: "linear",
- maxStartPrice: 1,
- maxCpuPerHourPrice: 1,
- maxEnvPerHourPrice: 1,
+ maxStartPrice: 0.5,
+ maxCpuPerHourPrice: 1.0,
+ maxEnvPerHourPrice: 0.5,
},
},
});
@@ -58,15 +60,19 @@ app.post("/tts", async (req, res) => {
await exe
.beginBatch()
.run(`espeak "${req.body}" -w /golem/output/output.wav`)
- .downloadFile("/golem/output/output.wav", `public/${fileName}`)
+ .downloadFile("/golem/output/output.wav", `${publicDirectoryPath}/${fileName}`)
.end();
return fileName;
});
- res.send(`Job started! ID: ${job.id}`);
+ res.send(
+ `Job started! ID: ${job.id}\n` +
+ `You can check it's state by calling:\ncurl http://localhost:${port}/tts/${job.id}\n` +
+ `And it's results by calling:\ncurl http://localhost:${port}/tts/${job.id}/results\n`,
+ );
});
app.get("/tts/:id", async (req, res) => {
- const job = golemClient.getJobById(req.params.id);
+ const job = jobManager.getJobById(req.params.id);
if (!job) {
res.status(404).send("Job not found");
return;
@@ -75,10 +81,10 @@ app.get("/tts/:id", async (req, res) => {
});
// serve files in the /public directory
-app.use("/results", express.static("public"));
+app.use("/results", express.static(publicDirectoryPath));
app.get("/tts/:id/results", async (req, res) => {
- const job = golemClient.getJobById(req.params.id);
+ const job = jobManager.getJobById(req.params.id);
if (!job) {
res.status(404).send("Job not found");
return;
@@ -89,7 +95,7 @@ app.get("/tts/:id/results", async (req, res) => {
const results = await job.results;
res.send(
- `Job completed successfully! Open the following link in your browser to listen to the result: http://localhost:${port}/results/${results}`,
+ `Job completed successfully! Open the following link in your browser to listen to the result: http://localhost:${port}/results/${results}\n`,
);
});
@@ -98,8 +104,9 @@ app.listen(port, () => {
});
process.on("SIGINT", async () => {
+ console.log("Gracefully shutting down...");
// cancel and cleanup all running jobs
- await golemClient.close();
+ await jobManager.close();
process.exit(0);
});
diff --git a/examples/package.json b/examples/package.json
index f8f908bee..ceff24c42 100644
--- a/examples/package.json
+++ b/examples/package.json
@@ -36,7 +36,7 @@
},
"dependencies": {
"@golem-sdk/golem-js": "file:..",
- "@golem-sdk/pino-logger": "^1.0.1",
+ "@golem-sdk/pino-logger": "^1.0.2",
"commander": "^12.0.0",
"express": "^4.18.2",
"tsx": "^4.7.1"
diff --git a/examples/web/hello.html b/examples/web/hello.html
index 0e022139d..9b3af5e5b 100644
--- a/examples/web/hello.html
+++ b/examples/web/hello.html
@@ -115,11 +115,13 @@
Results
await glm.connect();
appendResults("Request for renting a provider machine");
const rental = await glm.oneOf({ order });
+ appendResults("Rented resources from", rental.agreement.provider.name);
await rental
.getExeUnit()
.then(async (exe) =>
appendResults("Reply: " + (await exe.run(`echo 'Hello Golem! 👋 from ${exe.provider.name}!'`)).stdout),
);
+ appendResults("Finished all work with the resources");
await rental.stopAndFinalize();
appendResults("Finalized renting process");
} catch (err) {
diff --git a/package-lock.json b/package-lock.json
index d484ec3c9..c812c221d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -12,6 +12,7 @@
"examples/"
],
"dependencies": {
+ "@golem-sdk/pino-logger": "^1.1.0",
"async-lock": "^1.4.1",
"async-retry": "^1.3.3",
"axios": "^1.6.7",
@@ -33,7 +34,7 @@
"devDependencies": {
"@commitlint/cli": "^19.0.3",
"@commitlint/config-conventional": "^19.0.3",
- "@johanblumenberg/ts-mockito": "^1.0.41",
+ "@johanblumenberg/ts-mockito": "^1.0.43",
"@rollup/plugin-alias": "^5.1.0",
"@rollup/plugin-commonjs": "^25.0.7",
"@rollup/plugin-json": "^6.1.0",
@@ -98,7 +99,7 @@
"license": "LGPL-3.0",
"dependencies": {
"@golem-sdk/golem-js": "file:..",
- "@golem-sdk/pino-logger": "^1.0.1",
+ "@golem-sdk/pino-logger": "^1.0.2",
"commander": "^12.0.0",
"express": "^4.18.2",
"tsx": "^4.7.1"
@@ -1459,9 +1460,9 @@
"link": true
},
"node_modules/@golem-sdk/pino-logger": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/@golem-sdk/pino-logger/-/pino-logger-1.0.3.tgz",
- "integrity": "sha512-P9BMJ+QUlWx7C+4iku/SOnNnjzGGBEhaHtOf4IDXrtvpEg8zqxEuyw5mM7PXpAr7HU/5C/f2BcBG39i7QYfwsw==",
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@golem-sdk/pino-logger/-/pino-logger-1.1.0.tgz",
+ "integrity": "sha512-FxVqTnx7ToKPCABzfEHhwXT2x/B4PWez6y6AG9AeMjH9DA/itY8kclv0DUgWPPRTW4jr1Qrf6ovZYLhPZ5o3Dw==",
"dependencies": {
"pino": "^8.20.0",
"pino-pretty": "^11.0.0"
@@ -2340,9 +2341,10 @@
}
},
"node_modules/@johanblumenberg/ts-mockito": {
- "version": "1.0.41",
+ "version": "1.0.43",
+ "resolved": "https://registry.npmjs.org/@johanblumenberg/ts-mockito/-/ts-mockito-1.0.43.tgz",
+ "integrity": "sha512-7C1JMJzYPLmW4/nFZHTQTog/wRnB45UUU3hEur1p7HJDlpQpybQWAbE8yA+mBk+95mOEfuIVNcebSAB/KGrE0w==",
"dev": true,
- "license": "MIT",
"dependencies": {
"lodash": "^4.17.20"
}
@@ -2963,9 +2965,9 @@
]
},
"node_modules/@rollup/rollup-darwin-x64": {
- "version": "4.18.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.18.0.tgz",
- "integrity": "sha512-n2LMsUz7Ynu7DoQrSQkBf8iNrjOGyPLrdSg802vk6XT3FtsgX6JbE8IHRvposskFm9SNxzkLYGSq9QdpLYpRNA==",
+ "version": "4.18.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.18.1.tgz",
+ "integrity": "sha512-IgpzXKauRe1Tafcej9STjSSuG0Ghu/xGYH+qG6JwsAUxXrnkvNHcq/NL6nz1+jzvWAnQkuAJ4uIwGB48K9OCGA==",
"cpu": [
"x64"
],
@@ -3079,9 +3081,9 @@
]
},
"node_modules/@rollup/rollup-win32-arm64-msvc": {
- "version": "4.18.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.18.0.tgz",
- "integrity": "sha512-7J6TkZQFGo9qBKH0pk2cEVSRhJbL6MtfWxth7Y5YmZs57Pi+4x6c2dStAUvaQkHQLnEQv1jzBUW43GvZW8OFqA==",
+ "version": "4.18.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.18.1.tgz",
+ "integrity": "sha512-W2ZNI323O/8pJdBGil1oCauuCzmVd9lDmWBBqxYZcOqWD6aWqJtVBQ1dFrF4dYpZPks6F+xCZHfzG5hYlSHZ6g==",
"cpu": [
"arm64"
],
@@ -3104,9 +3106,9 @@
]
},
"node_modules/@rollup/rollup-win32-x64-msvc": {
- "version": "4.18.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.18.0.tgz",
- "integrity": "sha512-UOo5FdvOL0+eIVTgS4tIdbW+TtnBLWg1YBCcU2KWM7nuNwRz9bksDX1bekJJCpu25N1DVWaCwnT39dVQxzqS8g==",
+ "version": "4.18.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.18.1.tgz",
+ "integrity": "sha512-yjk2MAkQmoaPYCSu35RLJ62+dz358nE83VfTePJRp8CG7aMg25mEJYpXFiD+NcevhX8LxD5OP5tktPXnXN7GDw==",
"cpu": [
"x64"
],
@@ -3903,9 +3905,10 @@
"dev": true
},
"node_modules/@types/ws": {
- "version": "8.5.10",
+ "version": "8.5.11",
+ "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.11.tgz",
+ "integrity": "sha512-4+q7P5h3SpJxaBft0Dzpbr6lmMaqh0Jr2tbhJZ/luAwvD7ohSCniYkwz/pLxuT2h0EOa6QADgJj1Ko+TzRfZ+w==",
"dev": true,
- "license": "MIT",
"dependencies": {
"@types/node": "*"
}
@@ -18179,9 +18182,9 @@
}
},
"node_modules/tsx": {
- "version": "4.16.0",
- "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.16.0.tgz",
- "integrity": "sha512-MPgN+CuY+4iKxGoJNPv+1pyo5YWZAQ5XfsyobUG+zoKG7IkvCPLZDEyoIb8yLS2FcWci1nlxAqmvPlFWD5AFiQ==",
+ "version": "4.16.2",
+ "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.16.2.tgz",
+ "integrity": "sha512-C1uWweJDgdtX2x600HjaFaucXTilT7tgUZHbOE4+ypskZ1OP8CRCSDkCxG6Vya9EwaFIVagWwpaVAn5wzypaqQ==",
"dependencies": {
"esbuild": "~0.21.5",
"get-tsconfig": "^4.7.5"
@@ -18929,9 +18932,9 @@
"license": "ISC"
},
"node_modules/ws": {
- "version": "8.17.1",
- "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
- "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
+ "version": "8.18.0",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz",
+ "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==",
"engines": {
"node": ">=10.0.0"
},
diff --git a/package.json b/package.json
index 1f3c42dc0..72ca267f1 100644
--- a/package.json
+++ b/package.json
@@ -18,11 +18,13 @@
"exports": {
".": {
"types": "./dist/index.d.ts",
+ "browser": "./dist/golem-js.min.js",
"import": "./dist/golem-js.mjs",
"require": "./dist/golem-js.js"
},
"./experimental": {
- "types": "./dist/experimental.d.ts",
+ "types": "./dist/experimental/index.d.ts",
+ "browser": null,
"import": "./dist/golem-js-experimental.mjs",
"require": "./dist/golem-js-experimental.js"
}
@@ -61,6 +63,7 @@
"node": ">=18.0.0"
},
"dependencies": {
+ "@golem-sdk/pino-logger": "^1.1.0",
"async-lock": "^1.4.1",
"async-retry": "^1.3.3",
"axios": "^1.6.7",
@@ -82,7 +85,7 @@
"devDependencies": {
"@commitlint/cli": "^19.0.3",
"@commitlint/config-conventional": "^19.0.3",
- "@johanblumenberg/ts-mockito": "^1.0.41",
+ "@johanblumenberg/ts-mockito": "^1.0.43",
"@rollup/plugin-alias": "^5.1.0",
"@rollup/plugin-commonjs": "^25.0.7",
"@rollup/plugin-json": "^6.1.0",
diff --git a/src/activity/exe-script-executor.ts b/src/activity/exe-script-executor.ts
index 266fadf96..de768b190 100644
--- a/src/activity/exe-script-executor.ts
+++ b/src/activity/exe-script-executor.ts
@@ -65,7 +65,7 @@ export class ExeScriptExecutor {
const batchId = await this.send(script);
const batchSize = JSON.parse(script.text).length;
- this.logger.debug(`Script sent.`, { batchId });
+ this.logger.debug(`Script sent.`, { batchId, script });
return { batchId, batchSize };
} catch (error) {
const message = getMessageFromApiError(error);
@@ -175,7 +175,8 @@ export class ExeScriptExecutor {
}
} catch (error) {
logger.debug(`Failed to fetch activity results. Attempt: ${attempt}. ${error}`);
- if (RETRYABLE_ERROR_STATUS_CODES.includes(error?.status)) {
+ const errorStatus = error?.status ?? error.previous?.status;
+ if (RETRYABLE_ERROR_STATUS_CODES.includes(errorStatus)) {
throw error;
} else {
bail(error);
@@ -235,7 +236,7 @@ export class ExeScriptExecutor {
private parseEventToResult(event: StreamingBatchEvent, batchSize: number): Result {
// StreamingBatchEvent has a slightly more extensive structure,
// including a return code that could be added to the Result entity... (?)
- return new Result({
+ const result = new Result({
index: event.index,
eventDate: event.timestamp,
result: event?.kind?.finished
@@ -250,5 +251,9 @@ export class ExeScriptExecutor {
message: event?.kind?.finished?.message,
isBatchFinished: event.index + 1 >= batchSize && Boolean(event?.kind?.finished),
});
+
+ this.logger.debug("Received stream batch execution result", { result });
+
+ return result;
}
}
diff --git a/src/activity/exe-unit/batch.ts b/src/activity/exe-unit/batch.ts
index b39ea8c8c..c7f57dca6 100644
--- a/src/activity/exe-unit/batch.ts
+++ b/src/activity/exe-unit/batch.ts
@@ -109,7 +109,7 @@ export class Batch {
this.executor.activity.agreement.provider,
error,
);
- this.logger.debug("Error in batch script execution");
+ this.logger.debug("Error in batch script execution", { error });
this.script
.after(allResults)
.then(() => reject(golemError))
diff --git a/src/activity/exe-unit/process.ts b/src/activity/exe-unit/process.ts
index 44c69d0a0..a7ef22b3d 100644
--- a/src/activity/exe-unit/process.ts
+++ b/src/activity/exe-unit/process.ts
@@ -95,4 +95,11 @@ export class RemoteProcess {
this.subscription.add(() => end());
});
}
+
+ /**
+ * Checks if the exe-script batch from Yagna has completed, reflecting all work and streaming to be completed
+ */
+ isFinished() {
+ return this.lastResult?.isBatchFinished ?? false;
+ }
}
diff --git a/src/experimental/job/job.ts b/src/experimental/job/job.ts
index da208eef5..dad128af5 100644
--- a/src/experimental/job/job.ts
+++ b/src/experimental/job/job.ts
@@ -134,24 +134,22 @@ export class Job