Skip to content

Commit d6d7621

Browse files
authored
Merge pull request #1185 from golemfactory/beta
Beta
2 parents 519388b + 874a0d9 commit d6d7621

File tree

9 files changed

+60
-22
lines changed

9 files changed

+60
-22
lines changed

src/activity/activity.module.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,7 @@ export class ActivityModuleImpl implements ActivityModule {
301301
this.logger.debug("Initializing the exe-unit for activity", { activityId: activity.id });
302302

303303
try {
304-
await exe.setup();
304+
await exe.setup(options?.setupSignalOrTimeout);
305305
const refreshedActivity = await this.refreshActivity(activity).catch(() => {
306306
this.logger.warn("Failed to refresh activity after work context initialization", { activityId: activity.id });
307307
return activity;

src/activity/exe-unit/exe-unit.ts

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,17 @@ export interface ExeUnitOptions {
4545
/** this function is called before the exe unit is destroyed */
4646
teardown?: LifecycleFunction;
4747
executionOptions?: ExecutionOptions;
48+
/**
49+
* Abort signal or timeout for the entire lifecycle of the exe unit.
50+
* If this signal is aborted or timeout is reached at any point, all ongoing operations
51+
* will be stopped, no matter if it's activity deployment, setup, command execution or teardown.
52+
*/
4853
signalOrTimeout?: number | AbortSignal;
54+
/**
55+
* Abort signal or timeout for the setup phase only.
56+
* If this signal is aborted or timeout is reached after the setup phase is completed, it will be ignored.
57+
*/
58+
setupSignalOrTimeout?: number | AbortSignal;
4959
volumes?: Record<string, VolumeSpec>;
5060
}
5161

@@ -115,21 +125,41 @@ export class ExeUnit {
115125
* This function initializes the exe unit by deploying the image to the remote machine
116126
* and preparing and running the environment.
117127
* This process also includes running setup function if the user has defined it
128+
*
129+
* @param signalOrTimeout - Abort signal or timeout for the setup phase only.
130+
* If this signal is aborted or timeout is reached after the setup phase is completed, it will be ignored.
118131
*/
119-
async setup(): Promise<Result[] | void> {
132+
async setup(signalOrTimeout?: number | AbortSignal): Promise<Result[] | void> {
133+
const setupSignal = createAbortSignalFromTimeout(signalOrTimeout);
134+
const throwIfAborted = () => {
135+
if (this.abortSignal.aborted) {
136+
throw new GolemAbortError("ExeUnit has been aborted", this.abortSignal.reason);
137+
}
138+
if (setupSignal.aborted) {
139+
throw setupSignal.reason.name === "TimeoutError"
140+
? new GolemTimeoutError("ExeUnit setup has been aborted due to a timeout", setupSignal.reason)
141+
: new GolemAbortError("ExeUnit setup has been aborted", setupSignal.reason);
142+
}
143+
};
120144
try {
145+
throwIfAborted();
121146
let state = await this.fetchState();
147+
throwIfAborted();
148+
122149
if (state === ActivityStateEnum.Ready) {
123150
await this.setupActivity();
124151
return;
125152
}
126153

127154
if (state === ActivityStateEnum.Initialized) {
128-
await this.deployActivity();
155+
await this.deployActivity(setupSignal);
156+
throwIfAborted();
129157
}
130158

131159
await sleep(1000, true);
160+
throwIfAborted();
132161
state = await this.fetchState();
162+
throwIfAborted();
133163

134164
if (state !== ActivityStateEnum.Ready) {
135165
throw new GolemWorkError(
@@ -141,6 +171,7 @@ export class ExeUnit {
141171
);
142172
}
143173
await this.setupActivity();
174+
throwIfAborted();
144175
} catch (error) {
145176
if (this.abortSignal.aborted) {
146177
throw this.abortSignal.reason.name === "TimeoutError"
@@ -164,7 +195,7 @@ export class ExeUnit {
164195
}
165196
}
166197

167-
private async deployActivity() {
198+
private async deployActivity(setupAbortSignal?: AbortSignal) {
168199
try {
169200
const executionMetadata = await this.executor.execute(
170201
new Script([
@@ -175,7 +206,7 @@ export class ExeUnit {
175206
new Start(),
176207
]).getExeScriptRequest(),
177208
);
178-
const result$ = this.executor.getResultsObservable(executionMetadata);
209+
const result$ = this.executor.getResultsObservable(executionMetadata, false, setupAbortSignal);
179210
// if any result is an error, throw an error
180211
await lastValueFrom(
181212
result$.pipe(

src/golem-network/golem-network.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -607,7 +607,7 @@ export class GolemNetwork {
607607
* @param options.order - represents the order specifications which will result in access to LeaseProcess.
608608
* @param options.poolSize {Object | number} - can be defined as a number or an object with min and max fields, if defined as a number it will be treated as a min parameter.
609609
* @param options.poolSize.min - the minimum pool size to achieve ready state (default = 0)
610-
* @param options.poolSize.max - the maximum pool size, if reached, the next pool element will only be available if the borrowed resource is released or destroyed (dafault = 100)
610+
* @param options.poolSize.max - the maximum pool size, if reached, the next pool element will only be available if the borrowed resource is released or destroyed (default = 100)
611611
* @param options.setup - an optional function that is called as soon as the exe unit is ready
612612
* @param options.teardown - an optional function that is called before the exe unit is destroyed
613613
*/

src/market/demand/demand.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ export type OrderDemandOptions = Partial<{
8888
/** Demand properties that determine payment related terms & conditions of the agreement */
8989
payment: Partial<PaymentDemandDirectorConfigOptions>;
9090
}> &
91-
/** Demand properties that determine most common paramters of the agreement (based on golemsp implementation */
91+
/** Demand properties that determine most common parameters of the agreement (based on golemsp implementation */
9292
Partial<BasicDemandDirectorConfigOptions>;
9393

9494
export interface IDemandRepository {

src/market/market.module.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ export interface MarketModule {
207207
}): Observable<OfferProposal>;
208208

209209
/**
210-
* Estimate the budget for the given order and maximum numbers of agreemnets.
210+
* Estimate the budget for the given order and maximum numbers of agreements.
211211
* Keep in mind that this is just an estimate and the actual cost may vary.
212212
* The method returns the estimated budget in GLM.
213213
* @param params

src/network/network.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ describe("Network", () => {
6464
new GolemNetworkError(`Unable to add node network-node-id to removed network`, NetworkErrorCode.NetworkRemoved),
6565
);
6666
});
67-
test("should get first avialble ip adrress", () => {
67+
test("should get first avialble ip address", () => {
6868
const network = new Network("network-id", "192.168.0.0/24");
6969
expect(network.getFirstAvailableIpAddress().toString()).toEqual("192.168.0.1");
7070
});

src/resource-rental/resource-rental.ts

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -143,18 +143,11 @@ export class ResourceRental {
143143
if (this.currentExeUnit !== null) {
144144
return this.currentExeUnit;
145145
}
146-
const abortController = new AbortController();
147-
this.finalizeAbortController.signal.addEventListener("abort", () =>
148-
abortController.abort(this.finalizeAbortController.signal.reason),
149-
);
150-
if (signalOrTimeout) {
151-
const abortSignal = createAbortSignalFromTimeout(signalOrTimeout);
152-
abortSignal.addEventListener("abort", () => abortController.abort(abortSignal.reason));
153-
if (signalOrTimeout instanceof AbortSignal && signalOrTimeout.aborted) {
154-
abortController.abort(signalOrTimeout.reason);
155-
}
146+
const signal = createAbortSignalFromTimeout(signalOrTimeout);
147+
if (signal.aborted) {
148+
throw new GolemAbortError("Initializing of the exe-unit has been aborted", signal.reason);
156149
}
157-
return this.createExeUnit(abortController.signal);
150+
return this.createExeUnit(signal);
158151
}
159152

160153
/**
@@ -194,7 +187,8 @@ export class ResourceRental {
194187
storageProvider: this.storageProvider,
195188
networkNode: this.resourceRentalOptions?.networkNode,
196189
executionOptions: this.resourceRentalOptions?.activity,
197-
signalOrTimeout: abortSignal,
190+
signalOrTimeout: this.finalizeAbortController.signal,
191+
setupSignalOrTimeout: this.setupAbortController.signal,
198192
...this.resourceRentalOptions?.exeUnit,
199193
});
200194
this.events.emit("exeUnitCreated", activity);

src/shared/yagna/adapters/market-api-adapter.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import { cancelYagnaApiCall } from "../../utils/cancel";
2626
/**
2727
* A bit more user-friendly type definition of DemandOfferBaseDTO from ya-ts-client
2828
*
29-
* That's probably one of the most confusing elements around Golem Protocol and the API specificiation:
29+
* That's probably one of the most confusing elements around Golem Protocol and the API specification:
3030
*
3131
* - Providers create Offers
3232
* - Requestors create Demands

tests/e2e/resourceRentalPool.spec.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,19 @@ describe("ResourceRentalPool", () => {
220220
);
221221
});
222222

223+
it("should not interrupt running commands on the exe-unit when aborting the setup signal after setup is done", async () => {
224+
const pool = glm.rental.createResourceRentalPool(proposalPool, allocation, { poolSize: 1 });
225+
const rental = await pool.acquire();
226+
const abortController = new AbortController();
227+
const exeUnit = await rental.getExeUnit(abortController.signal);
228+
const runPromise = exeUnit.run("sleep 5 && echo Hello World");
229+
// wait 2 seconds and abort the signal - the setup is already done so it should not affect the running command
230+
await new Promise((res) => setTimeout(res, 2000));
231+
abortController.abort();
232+
const result = await runPromise;
233+
expect(result.stdout?.toString().trim()).toEqual("Hello World");
234+
});
235+
223236
it("should abort getting the newly created exe-unit by signal", async () => {
224237
const pool = glm.rental.createResourceRentalPool(proposalPool, allocation, { poolSize: 1 });
225238
const abortController = new AbortController();

0 commit comments

Comments
 (0)