Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rename WorkContext to ExeUnit #982

Merged
merged 20 commits into from
Jun 20, 2024
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
70c8ed0
refactor(work-context): rename WorkContext to ExeUnit
mgordel Jun 18, 2024
12a488f
docs: fixed typedoc link
mgordel Jun 18, 2024
31c4dcc
refactor: changed ctx to exe unit in logs
mgordel Jun 18, 2024
1fd6eac
feat: added setup and teardown functions as options to exe-unit
mgordel Jun 19, 2024
5fa2fb8
chore: sync beta
mgordel Jun 19, 2024
5c120ba
docs: added example of the setup and terdown functions
mgordel Jun 19, 2024
2c73ba0
test: fixed oneOf params in unit test
mgordel Jun 19, 2024
387aee4
docs: fixed oneOf params in example
mgordel Jun 19, 2024
1cd8f00
refactor(exe-unit): renamed `before` method to `setup` and added `tea…
mgordel Jun 19, 2024
9dda67d
docs: added typedoc comments for oneOf and manyOf
mgordel Jun 19, 2024
dee024e
docs: added example (rendering) of using the setup and teardown funct…
mgordel Jun 19, 2024
8b27838
test: fixed after removing fixtures
mgordel Jun 19, 2024
55fcaa5
chore: sync beta
mgordel Jun 20, 2024
80f0736
docs: removed rendering example
mgordel Jun 20, 2024
f65e0e0
docs: example for setup and teardown
SewerynKras Jun 20, 2024
413cde3
docs: document setup and teardown in README
SewerynKras Jun 20, 2024
d04e8f4
Merge pull request #986 from golemfactory/decryption-example
mgordel Jun 20, 2024
a9336a7
docs: use golem image in setup and teardown example
SewerynKras Jun 20, 2024
0ba718a
refactor: changed remaining `lease` names to `rental`
mgordel Jun 20, 2024
042c76b
Merge remote-tracking branch 'origin/mgordel/JST-984/exe-unit-rename'…
mgordel Jun 20, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
- [Custom filters](#custom-filters)
- [Custom ranking of proposals](#custom-ranking-of-proposals)
- [Uploading local images to the provider](#uploading-local-images-to-the-provider)
- [Setup and teardown methods](#setup-and-teardown-methods)
- [Going further](#going-further)
- [More examples](#more-examples)
- [Debugging](#debugging)
Expand Down Expand Up @@ -356,6 +357,29 @@ const order: MarketOrderSpec = {

[Check the full example](./examples/advanced//local-image/)

### Setup and teardown methods

You can define a setup method that will be executed the first time a provider is rented and a teardown method
that will be executed before the rental is done. This is useful when you want to avoid doing the same work
multiple times when running multiple tasks on the same provider.

```ts
// I want to upload a big file to each provider only once
const setup: LifecycleFunction = async (exe) => exe.uploadFile("./big-file.txt", "/golem/work/big-file.txt");

// I want to remove the file after I'm done
const teardown: LifecycleFunction = async (exe) => exe.run("rm /golem/work/big-file.txt");

const pool = await glm.manyOf({
order,
concurrency,
setup,
teardown,
});
```

[Check the full example](./examples/advanced/setup-and-teardown.ts)

<!--
TODO:
### Market scan
Expand Down
2 changes: 1 addition & 1 deletion examples/advanced/local-image/serveLocalGvmi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ const getImagePath = (path: string) => new URL(path, import.meta.url).toString()
},
};

const lease = await glm.oneOf({ order });
const rental = await glm.oneOf({ order });
// in our Dockerfile we have created a file called hello.txt, let's read it
const result = await rental
.getExeUnit()
Expand Down
4 changes: 2 additions & 2 deletions examples/advanced/override-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ const order: MarketOrderSpec = {

try {
await glm.connect();
const lease = await glm.oneOf({ order });
await lease
const rental = await glm.oneOf({ order });
await rental
.getExeUnit()
.then((exe) => exe.run("echo Hello, Golem! 👋"))
.then((res) => console.log(res.stdout));
Expand Down
4 changes: 2 additions & 2 deletions examples/advanced/payment-filters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@ const order: MarketOrderSpec = {

try {
await glm.connect();
const lease = await glm.oneOf({ order });
await lease
const rental = await glm.oneOf({ order });
await rental
.getExeUnit()
.then((exe) => exe.run("echo Hello, Golem! 👋"))
.then((res) => console.log(res.stdout));
Expand Down
4 changes: 2 additions & 2 deletions examples/advanced/proposal-filter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ const order: MarketOrderSpec = {

try {
await glm.connect();
const lease = await glm.oneOf({ order });
await lease
const rental = await glm.oneOf({ order });
await rental
.getExeUnit()
.then((exe) => exe.run(`echo [provider:${exe.provider.name}] Hello, Golem! 👋`))
.then((res) => console.log(res.stdout));
Expand Down
4 changes: 2 additions & 2 deletions examples/advanced/proposal-predefined-filter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ const order: MarketOrderSpec = {

try {
await glm.connect();
const lease = await glm.oneOf({ order });
await lease
const rental = await glm.oneOf({ order });
await rental
.getExeUnit()
.then((exe) => exe.run(`echo [provider:${exe.provider.name}] Hello, Golem! 👋`))
.then((res) => console.log(res.stdout));
Expand Down
4 changes: 2 additions & 2 deletions examples/advanced/proposal-selector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ const order: MarketOrderSpec = {

try {
await glm.connect();
const lease = await glm.oneOf({ order });
await lease
const rental = await glm.oneOf({ order });
await rental
.getExeUnit()
.then((exe) => exe.run(`echo [provider:${exe.provider.name}] Hello, Golem! 👋`))
.then((res) => console.log(res.stdout));
Expand Down
4 changes: 2 additions & 2 deletions examples/advanced/reuse-allocation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ import { pinoPrettyLogger } from "@golem-sdk/pino-logger";
},
};

const lease1 = await glm.oneOf({ order: firstOrder });
const lease2 = await glm.oneOf({ order: secondOrder });
const rental1 = await glm.oneOf({ order: firstOrder });
const rental2 = await glm.oneOf({ order: secondOrder });

await rental1
.getExeUnit()
Expand Down
79 changes: 58 additions & 21 deletions examples/advanced/setup-and-teardown.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
/**
* This advanced example shows how to use the setup and teardown lifecycle functions
* to avoid doing the same work multiple times when running multiple tasks on the same provider.
*/
import { MarketOrderSpec, GolemNetwork, LifecycleFunction } from "@golem-sdk/golem-js";
import { pinoPrettyLogger } from "@golem-sdk/pino-logger";

const order: MarketOrderSpec = {
demand: {
workload: { imageTag: "golem/alpine:latest" },
workload: {
imageTag: "golem/examples-openssl:latest",
},
},
market: {
rentHours: 0.5,
Expand All @@ -16,46 +22,77 @@ const order: MarketOrderSpec = {
},
};

/**
* Let's decrypt these messages in parallel on multiple providers.
* We know that the messages were encrypted using the aes-256-cbc algorithm
* with 5000000 iterations and the password "golemnetwork".
*/
const secretMessages = `
U2FsdGVkX18S4g4iyUzjfqIwP/cGppD86mrVQ0kYerfSe3OnGORuU4nYLG6WXy5KG6vLVLq1N/jnyrwkT8yEBA==
U2FsdGVkX1+jEgVgmS+xu37tT5OHieX8cioZHPyjUTh+YodWf0In3DaqtFcEfw2cLHIBd94s4nEmONHCs9x4Rg==
U2FsdGVkX1+JU+fBsnKEGZHGoQpEY/DqlnbCQVg+KgLtkFbtjuHpQbMjnb7iBuj4o4yIYU00jM67+gqn89hrNA==
U2FsdGVkX1897oplQ7utV9zpx/86GABjUP29Xr/GsahKQ9eRv9GgnzW9BCqHKiFjiB2q2F6gCJINspbuiFY+Fg==
U2FsdGVkX183p8EUPOZj/QZFQSeIeYNSSfHcRrBF0NXSJ4RfibvT5HtJJ/5I9fVpc1XpbLwDsCW2yFdQKSzbXA==
U2FsdGVkX184PQiKxx8Sfvl+BOy9JYrBQqdMxWEDc3GBDkEb3qYCWL7FPxZpCEwoZ10MpvY1EKb4lMMxWth6bw==
U2FsdGVkX1/ujngC/IwK8UAvj41t/FbSHVFiiXI7+KeHoKW3HKcwZYb0E+nncpPC6ZT0DgWLzvDaUyBqOS+tkA==
U2FsdGVkX19GNHf4ORUAy2PC3MMnvjx7aZSRNSqkW20fZ03Dc2OnZEWBDPa1J4yx
U2FsdGVkX18iL21PNCohSdFuIOufknLXmINnYf3q15Fl+1vFcRnmC8b9zcrob5Iz/9dNkvrgAeNFmAwWK0bwPw==
U2FsdGVkX18jQbGQ7KTAaRask5efrXEWvvGhe4jQ0MT9mwwH4ULjvoWDm1mNlsjYtb1nRt0O6iBd4O9moHLbbg==
`.trim();

(async () => {
const glm = new GolemNetwork({
logger: pinoPrettyLogger({
level: "info",
// for this example we disable info logs to better show the output
level: "warn",
}),
});

try {
await glm.connect();

// I want to upload my encrypted messages to the provider before I start working
const setup: LifecycleFunction = async (exe) =>
exe
.run(`echo This code is run on the start of the exe-unit ${exe.provider.name}`)
.then((res) => console.log(res.stdout));
.run(`echo "${secretMessages}" > /golem/work/encrypted-messages.txt`)
.then(() => console.log("Uploaded the encrypted messages to the provider %s", exe.provider.name));

// I want to remove the encrypted messages from the provider after I finish working
const teardown: LifecycleFunction = async (exe) =>
exe
.run(`echo This code is run before the exe-unit ${exe.provider.name} is destroyed`)
.then((res) => console.log(res.stdout));
.run("rm /golem/work/encrypted-messages.txt")
.then(() => console.log("Removed the encrypted messages from the provider %s", exe.provider.name));

const pool = await glm.manyOf({
concurrency: 2,
concurrency: { max: 3 }, // I want to decrypt in parallel on a maximum of 3 machines simultaneously
order,
setup,
teardown,
});
await Promise.allSettled([
pool.withLease(async (lease) =>
lease
.getExeUnit()
.then((exe) => exe.run(`echo Hello, Golem from the first machine! 👋 ${exe.provider.name}`))
.then((res) => console.log(res.stdout)),
),
pool.withLease(async (lease) =>
lease
.getExeUnit()
.then((exe) => exe.run(`echo Hello, Golem from the second machine! 👋 ${exe.provider.name}`))
.then((res) => console.log(res.stdout)),
),
]);

// map each message to a decryption task
const decryptionTasks = new Array(10).fill(null).map((_, i) =>
pool.withRental(async (rental) => {
const exe = await rental.getExeUnit();
const result = await exe.run(
`sed '${i + 1}!d' /golem/work/encrypted-messages.txt | \
openssl \
enc -aes-256-cbc -d -a \
-pass pass:golemnetwork \
-iter 5000000`,
);
console.log("Finished decrypting message #%s on the provider %s", i + 1, exe.provider.name);
return String(result.stdout).trim();
}),
);
const decryptedMessages = await Promise.all(decryptionTasks);
await pool.drainAndClear();

console.log("Decrypted messages:");
for (const message of decryptedMessages) {
// display the decrypted messages in light-blue color
console.log("\x1b[36m%s\x1b[0m", message);
}
} catch (err) {
console.error("Failed to run the example", err);
} finally {
Expand Down
2 changes: 1 addition & 1 deletion examples/basic/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import { pinoPrettyLogger } from "@golem-sdk/pino-logger";
console.warn("Proposal rejected by provider", event);
});

const lease = await glm.oneOf({
const rental = await glm.oneOf({
order: {
demand: {
workload: { imageTag: "golem/alpine:latest" },
Expand Down
4 changes: 2 additions & 2 deletions examples/basic/one-of.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ const order: MarketOrderSpec = {

try {
await glm.connect();
const lease = await glm.oneOf({ order });
await lease
const rental = await glm.oneOf({ order });
await rental
.getExeUnit()
.then((exe) => exe.run("echo Hello, Golem! 👋"))
.then((res) => console.log(res.stdout));
Expand Down
4 changes: 2 additions & 2 deletions examples/basic/run-and-stream.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ const order: MarketOrderSpec = {

try {
await glm.connect();
const lease = await glm.oneOf({ order });
const exe = await lease.getExeUnit();
const rental = await glm.oneOf({ order });
const exe = await rental.getExeUnit();

const remoteProcess = await exe.runAndStream(
`
Expand Down
1 change: 1 addition & 0 deletions examples/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"advanced-payment-filters": "tsx advanced/payment-filters.ts",
"advanced-proposal-filters": "tsx advanced/proposal-filter.ts",
"advanced-proposal-predefined-filter": "tsx advanced/proposal-predefined-filter.ts",
"advanced-rendering": "tsx advanced/rendering.ts",
mgordel marked this conversation as resolved.
Show resolved Hide resolved
"local-image": "tsx advanced/local-image/serveLocalGvmi.ts",
"deployment": "tsx experimental/deployment/new-api.ts",
"market-scan": "tsx market/scan.ts",
Expand Down
6 changes: 3 additions & 3 deletions examples/web/hello.html
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,9 @@ <h3>Results</h3>
try {
appendResults("Establishing a connection to the Golem Network");
await glm.connect();
appendResults("Request for leasing a provider machine");
const lease = await glm.oneOf({ order });
await lease
appendResults("Request for renting a provider machine");
const rental = await glm.oneOf({ order });
await rental
.getExeUnit()
.then(async (exe) =>
appendResults("Reply: " + (await exe.run(`echo 'Hello Golem! 👋 from ${exe.provider.name}!'`)).stdout),
Expand Down
8 changes: 4 additions & 4 deletions src/experimental/job/job.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,19 @@ import { GolemNetwork } from "../../golem-network";
import { ResourceRental } from "../../resource-rental";

const mockGlm = mock(GolemNetwork);
const mockLease = mock(LeaseProcess);
const mockRental = mock(ResourceRental);
const mockExeUnit = mock(ExeUnit);
describe("Job", () => {
beforeEach(() => {
reset(mockGlm);
reset(mockLease);
reset(mockRental);
reset(mockExeUnit);
});

describe("cancel()", () => {
it("stops the activity and releases the agreement when canceled", async () => {
when(mockLease.getExeUnit()).thenResolve(instance(mockExeUnit));
when(mockGlm.oneOf(anything())).thenResolve(instance(mockLease));
when(mockRental.getExeUnit()).thenResolve(instance(mockExeUnit));
when(mockGlm.oneOf(anything())).thenResolve(instance(mockRental));
const job = new Job(
"test_id",
instance(mockGlm),
Expand Down
4 changes: 2 additions & 2 deletions src/experimental/job/job.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,9 +134,9 @@ export class Job<Output = unknown> {
throw new GolemAbortError("Canceled");
}

const lease = await this.glm.oneOf({ order: this.order });
const rental = await this.glm.oneOf({ order: this.order });

const exeUnit = await lease.getExeUnit();
const exeUnit = await rental.getExeUnit();
this.events.emit("started");

const onAbort = async () => {
Expand Down
4 changes: 2 additions & 2 deletions src/golem-network/golem-network.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ describe("Golem Network", () => {
const glm = getGolemNetwork();
await glm.connect();

const lease = await glm.oneOf({ order });
const rental = await glm.oneOf({ order });

expect(rental).toBe(mockResourceRentalInstance);

Expand All @@ -110,7 +110,7 @@ describe("Golem Network", () => {
const glm = getGolemNetwork();
await glm.connect();

const lease = await glm.oneOf({
const rental = await glm.oneOf({
order: {
...order,
payment: {
Expand Down
4 changes: 2 additions & 2 deletions src/golem-network/golem-network.ts
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,7 @@ export class GolemNetwork {
* @param options.setup - an optional function that is called as soon as the exe unit is ready
* @param options.teardown - an optional function that is called before the exe unit is destroyed
*/
async oneOf({ order, setup, teardown, signalOrTimeout }: OneOfOptions): Promise<LeaseProcess> {
async oneOf({ order, setup, teardown, signalOrTimeout }: OneOfOptions): Promise<ResourceRental> {
const proposalPool = new DraftOfferProposalPool({
logger: this.logger,
validateProposal: order.market.proposalFilter,
Expand Down Expand Up @@ -472,7 +472,7 @@ export class GolemNetwork {
* @param options.setup - an optional function that is called as soon as the exe unit is ready
* @param options.teardown - an optional function that is called before the exe unit is destroyed
*/
public async manyOf({ concurrency, order, setup, teardown }: ManyOfOptions): Promise<LeaseProcessPool> {
public async manyOf({ concurrency, order, setup, teardown }: ManyOfOptions): Promise<ResourceRentalPool> {
const proposalPool = new DraftOfferProposalPool({
logger: this.logger,
validateProposal: order.market.proposalFilter,
Expand Down
8 changes: 4 additions & 4 deletions src/resource-rental/resource-rental.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export interface ResourceRentalEvents {
finalized: () => void;
}

export interface LeaseProcessOptions {
export interface ResourceRentalOptions {
exeUnit?: Pick<ExeUnitOptions, "setup" | "teardown" | "activityDeployingTimeout">;
activity?: ExecutionOptions;
payment?: Partial<PaymentProcessOptions>;
Expand Down Expand Up @@ -105,10 +105,10 @@ export class ResourceRental {
const activity = await this.activityModule.createActivity(this.agreement);
this.currentExeUnit = await this.activityModule.createExeUnit(activity, {
storageProvider: this.storageProvider,
networkNode: this.leaseOptions?.networkNode,
executionOptions: this.leaseOptions?.activity,
networkNode: this.resourceRentalOptions?.networkNode,
executionOptions: this.resourceRentalOptions?.activity,
signalOrTimeout: this.abortController.signal,
...this.leaseOptions?.exeUnit,
...this.resourceRentalOptions?.exeUnit,
});

return this.currentExeUnit;
Expand Down
2 changes: 1 addition & 1 deletion src/shared/storage/ws-browser.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { GolemInternalError, Logger, nullLogger, WebSocketBrowserStorageProvider
// .js added for ESM compatibility
import { encode, toObject } from "flatbuffers/js/flexbuffers.js";
import * as jsSha3 from "js-sha3";
import { TEST_IDENTITY } from "../../../tests/fixtures";
import { GsbApi, IdentityApi } from "ya-ts-client";
import { anything, imock, instance, mock, reset, verify, when } from "@johanblumenberg/ts-mockito";

Expand All @@ -17,6 +16,7 @@ const mockIdentity = mock(IdentityApi.DefaultService);
const mockGsb = mock(GsbApi.RequestorService);
const logger = imock<Logger>();
const yagnaApi = instance(mockYagna);
const TEST_IDENTITY = "0x19ee20228a4c4bf8d4aebc79d9d3af2a01433456";

describe("WebSocketBrowserStorageProvider", () => {
const createProvider = () =>
Expand Down
Loading
Loading