fix: return statement is not necessary to execute .then and .catch execution (#16802)
This commit is contained in:
parent
cafb0d37b0
commit
a0646bca77
|
|
@ -1,6 +1,6 @@
|
||||||
import { ObjectsRegistry } from "../../../../support/Objects/Registry";
|
import { ObjectsRegistry } from "../../../../support/Objects/Registry";
|
||||||
|
|
||||||
let agHelper = ObjectsRegistry.AggregateHelper,
|
const agHelper = ObjectsRegistry.AggregateHelper,
|
||||||
ee = ObjectsRegistry.EntityExplorer,
|
ee = ObjectsRegistry.EntityExplorer,
|
||||||
jsEditor = ObjectsRegistry.JSEditor,
|
jsEditor = ObjectsRegistry.JSEditor,
|
||||||
locator = ObjectsRegistry.CommonLocators,
|
locator = ObjectsRegistry.CommonLocators,
|
||||||
|
|
@ -10,7 +10,7 @@ let agHelper = ObjectsRegistry.AggregateHelper,
|
||||||
|
|
||||||
describe("Validate basic Promises", () => {
|
describe("Validate basic Promises", () => {
|
||||||
it("1. Verify storeValue via .then via direct Promises", () => {
|
it("1. Verify storeValue via .then via direct Promises", () => {
|
||||||
let date = new Date().toDateString();
|
const date = new Date().toDateString();
|
||||||
cy.fixture("promisesBtnDsl").then((val: any) => {
|
cy.fixture("promisesBtnDsl").then((val: any) => {
|
||||||
agHelper.AddDsl(val, locator._spanButton("Submit"));
|
agHelper.AddDsl(val, locator._spanButton("Submit"));
|
||||||
});
|
});
|
||||||
|
|
@ -254,7 +254,7 @@ return InspiringQuotes.run().then((res) => { showAlert("Today's quote for " + us
|
||||||
|
|
||||||
it("9. Bug 10150: Verify Promise.all via JSObjects", () => {
|
it("9. Bug 10150: Verify Promise.all via JSObjects", () => {
|
||||||
deployMode.NavigateBacktoEditor();
|
deployMode.NavigateBacktoEditor();
|
||||||
let date = new Date().toDateString();
|
const date = new Date().toDateString();
|
||||||
cy.fixture("promisesBtnDsl").then((val: any) => {
|
cy.fixture("promisesBtnDsl").then((val: any) => {
|
||||||
agHelper.AddDsl(val, locator._spanButton("Submit"));
|
agHelper.AddDsl(val, locator._spanButton("Submit"));
|
||||||
});
|
});
|
||||||
|
|
@ -337,24 +337,27 @@ showAlert("Wonderful! all apis executed", "success")).catch(() => showAlert("Ple
|
||||||
"{{resetWidget('Input1').then(() => showAlert(Input1.text))}}",
|
"{{resetWidget('Input1').then(() => showAlert(Input1.text))}}",
|
||||||
);
|
);
|
||||||
deployMode.DeployApp(locator._widgetInputSelector("inputwidgetv2"));
|
deployMode.DeployApp(locator._widgetInputSelector("inputwidgetv2"));
|
||||||
agHelper.TypeText(locator._widgetInputSelector("inputwidgetv2"), "Update value")
|
agHelper.TypeText(
|
||||||
|
locator._widgetInputSelector("inputwidgetv2"),
|
||||||
|
"Update value",
|
||||||
|
);
|
||||||
agHelper.ClickButton("Submit");
|
agHelper.ClickButton("Submit");
|
||||||
agHelper.ValidateToastMessage("Test");
|
agHelper.ValidateToastMessage("Test");
|
||||||
});
|
});
|
||||||
|
|
||||||
//Skipping until this bug this is addressed!
|
it("12. Bug 9782: Verify .then & .catch (show alert should trigger) via JS Objects without return keyword", () => {
|
||||||
it.skip("12. Bug 9782: Verify .then & .catch (show alert should trigger) via JS Objects without return keyword", () => {
|
|
||||||
deployMode.NavigateBacktoEditor();
|
deployMode.NavigateBacktoEditor();
|
||||||
cy.fixture("promisesBtnDsl").then((val: any) => {
|
cy.fixture("promisesBtnDsl").then((val: any) => {
|
||||||
agHelper.AddDsl(val);
|
agHelper.AddDsl(val);
|
||||||
});
|
});
|
||||||
jsEditor.CreateJSObject(`const user = 'You';
|
jsEditor.CreateJSObject(`const user = 'You';
|
||||||
InspiringQuotes.run().then((res) => { showAlert("Today's quote for " + user + " is " + JSON.stringify(res.quote.body), 'success') }).catch(() => showAlert("Unable to fetch quote for " + user, 'warning'))`);
|
InspiringQuotes.run().then((res) => { showAlert("Today's quote for " + user + " is " + JSON.stringify(res.quote.body), 'success') }).catch(() => showAlert("Unable to fetch quote for " + user, 'warning'))`);
|
||||||
ee.SelectEntityByName("Button1");
|
ee.SelectEntityByName("Button1", "Widgets");
|
||||||
cy.get("@jsObjName").then((jsObjName) => {
|
cy.get("@jsObjName").then((jsObjName) => {
|
||||||
propPane.EnterJSContext("onClick", "{{" + jsObjName + ".myFun1()}}");
|
propPane.EnterJSContext("onClick", "{{" + jsObjName + ".myFun1()}}");
|
||||||
});
|
});
|
||||||
agHelper.ClickButton("Submit");
|
agHelper.ClickButton("Submit");
|
||||||
|
agHelper.Sleep(1000);
|
||||||
agHelper
|
agHelper
|
||||||
.GetNAssertContains(
|
.GetNAssertContains(
|
||||||
locator._toastMsg,
|
locator._toastMsg,
|
||||||
|
|
|
||||||
|
|
@ -251,6 +251,7 @@ export function* evaluateActionBindings(
|
||||||
* worker. Worker will evaluate a block of code and ask the main thread to execute it. The result of this
|
* worker. Worker will evaluate a block of code and ask the main thread to execute it. The result of this
|
||||||
* execution is returned to the worker where it can resolve/reject the current promise.
|
* execution is returned to the worker where it can resolve/reject the current promise.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export function* evaluateAndExecuteDynamicTrigger(
|
export function* evaluateAndExecuteDynamicTrigger(
|
||||||
dynamicTrigger: string,
|
dynamicTrigger: string,
|
||||||
eventType: EventType,
|
eventType: EventType,
|
||||||
|
|
@ -260,17 +261,23 @@ export function* evaluateAndExecuteDynamicTrigger(
|
||||||
) {
|
) {
|
||||||
const unEvalTree: DataTree = yield select(getUnevaluatedDataTree);
|
const unEvalTree: DataTree = yield select(getUnevaluatedDataTree);
|
||||||
log.debug({ execute: dynamicTrigger });
|
log.debug({ execute: dynamicTrigger });
|
||||||
|
const { isFinishedChannel } = yield call(
|
||||||
const { requestChannel, responseChannel } = yield call(
|
|
||||||
worker.duplexRequest,
|
worker.duplexRequest,
|
||||||
EVAL_WORKER_ACTIONS.EVAL_TRIGGER,
|
EVAL_WORKER_ACTIONS.EVAL_TRIGGER,
|
||||||
{ dataTree: unEvalTree, dynamicTrigger, callbackData, globalContext },
|
{
|
||||||
|
dataTree: unEvalTree,
|
||||||
|
dynamicTrigger,
|
||||||
|
callbackData,
|
||||||
|
globalContext,
|
||||||
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
let keepAlive = true;
|
let keepAlive = true;
|
||||||
|
|
||||||
while (keepAlive) {
|
while (keepAlive) {
|
||||||
const { requestData } = yield take(requestChannel);
|
const { requestData } = yield take(isFinishedChannel);
|
||||||
log.debug({ requestData, eventType, triggerMeta, dynamicTrigger });
|
log.debug({ requestData, eventType, triggerMeta, dynamicTrigger });
|
||||||
|
|
||||||
if (requestData.finished) {
|
if (requestData.finished) {
|
||||||
keepAlive = false;
|
keepAlive = false;
|
||||||
|
|
||||||
|
|
@ -326,20 +333,38 @@ export function* evaluateAndExecuteDynamicTrigger(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// Return value of a promise is returned
|
// Return value of a promise is returned
|
||||||
|
isFinishedChannel.close();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
yield call(evalErrorHandler, requestData.errors);
|
yield call(evalErrorHandler, requestData.errors);
|
||||||
if (requestData.trigger) {
|
isFinishedChannel.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function* executeDynamicTriggerRequest(
|
||||||
|
mainThreadRequestChannel: Channel<any>,
|
||||||
|
) {
|
||||||
|
while (true) {
|
||||||
|
const { mainThreadResponseChannel, requestData, requestId } = yield take(
|
||||||
|
mainThreadRequestChannel,
|
||||||
|
);
|
||||||
|
log.debug({ requestData });
|
||||||
|
if (requestData?.trigger) {
|
||||||
// if we have found a trigger, we need to execute it and respond back
|
// if we have found a trigger, we need to execute it and respond back
|
||||||
log.debug({ trigger: requestData.trigger });
|
log.debug({ trigger: requestData.trigger });
|
||||||
yield spawn(
|
yield spawn(
|
||||||
executeTriggerRequestSaga,
|
executeTriggerRequestSaga,
|
||||||
|
requestId,
|
||||||
requestData,
|
requestData,
|
||||||
eventType,
|
requestData.eventType,
|
||||||
responseChannel,
|
mainThreadResponseChannel,
|
||||||
triggerMeta,
|
requestData.triggerMeta,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (requestData?.errors) {
|
||||||
|
yield call(evalErrorHandler, requestData.errors);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -357,9 +382,10 @@ interface ResponsePayload {
|
||||||
* resolve or reject it with the data the execution has provided
|
* resolve or reject it with the data the execution has provided
|
||||||
*/
|
*/
|
||||||
function* executeTriggerRequestSaga(
|
function* executeTriggerRequestSaga(
|
||||||
|
requestId: string,
|
||||||
requestData: { trigger: ActionDescription; subRequestId: string },
|
requestData: { trigger: ActionDescription; subRequestId: string },
|
||||||
eventType: EventType,
|
eventType: EventType,
|
||||||
responseChannel: Channel<unknown>,
|
responseFromExecutionChannel: Channel<unknown>,
|
||||||
triggerMeta: TriggerMeta,
|
triggerMeta: TriggerMeta,
|
||||||
) {
|
) {
|
||||||
const responsePayload: ResponsePayload = {
|
const responsePayload: ResponsePayload = {
|
||||||
|
|
@ -386,8 +412,9 @@ function* executeTriggerRequestSaga(
|
||||||
responsePayload.data.reason = { message: error.message };
|
responsePayload.data.reason = { message: error.message };
|
||||||
responsePayload.success = false;
|
responsePayload.success = false;
|
||||||
}
|
}
|
||||||
responseChannel.put({
|
responseFromExecutionChannel.put({
|
||||||
method: EVAL_WORKER_ACTIONS.PROCESS_TRIGGER,
|
method: EVAL_WORKER_ACTIONS.PROCESS_TRIGGER,
|
||||||
|
requestId: requestId,
|
||||||
...responsePayload,
|
...responsePayload,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -548,8 +575,11 @@ function getPostEvalActions(
|
||||||
function* evaluationChangeListenerSaga() {
|
function* evaluationChangeListenerSaga() {
|
||||||
// Explicitly shutdown old worker if present
|
// Explicitly shutdown old worker if present
|
||||||
yield call(worker.shutdown);
|
yield call(worker.shutdown);
|
||||||
yield call(worker.start);
|
const { mainThreadRequestChannel } = yield call(worker.start);
|
||||||
|
|
||||||
yield call(worker.request, EVAL_WORKER_ACTIONS.SETUP);
|
yield call(worker.request, EVAL_WORKER_ACTIONS.SETUP);
|
||||||
|
yield spawn(executeDynamicTriggerRequest, mainThreadRequestChannel);
|
||||||
|
|
||||||
widgetTypeConfigMap = WidgetFactory.getWidgetTypeConfigMap();
|
widgetTypeConfigMap = WidgetFactory.getWidgetTypeConfigMap();
|
||||||
const initAction: {
|
const initAction: {
|
||||||
postEvalActions: Array<ReduxAction<unknown>>;
|
postEvalActions: Array<ReduxAction<unknown>>;
|
||||||
|
|
|
||||||
|
|
@ -228,8 +228,7 @@ describe("GracefulWorkerService", () => {
|
||||||
requestData,
|
requestData,
|
||||||
);
|
);
|
||||||
const handlers = await duplexRequest.toPromise();
|
const handlers = await duplexRequest.toPromise();
|
||||||
expect(handlers).toHaveProperty("requestChannel");
|
expect(handlers).toHaveProperty("isFinishedChannel");
|
||||||
expect(handlers).toHaveProperty("responseChannel");
|
|
||||||
expect(MockWorker.instance.postMessage).toBeCalledWith({
|
expect(MockWorker.instance.postMessage).toBeCalledWith({
|
||||||
method,
|
method,
|
||||||
requestData,
|
requestData,
|
||||||
|
|
@ -237,54 +236,6 @@ describe("GracefulWorkerService", () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test("duplex request channel handler", async () => {
|
|
||||||
const w = new GracefulWorkerService(MockWorker);
|
|
||||||
await runSaga({}, w.start);
|
|
||||||
const mockChannel = (name = "mock") => ({
|
|
||||||
name,
|
|
||||||
take: jest.fn(),
|
|
||||||
put: jest.fn(),
|
|
||||||
flush: jest.fn(),
|
|
||||||
close: jest.fn(),
|
|
||||||
});
|
|
||||||
const workerChannel = channel();
|
|
||||||
const mockRequestChannel = mockChannel("request");
|
|
||||||
const mockResponseChannel = mockChannel("response");
|
|
||||||
runSaga(
|
|
||||||
{},
|
|
||||||
// @ts-expect-error: type mismatch
|
|
||||||
w.duplexRequestHandler,
|
|
||||||
workerChannel,
|
|
||||||
mockRequestChannel,
|
|
||||||
mockResponseChannel,
|
|
||||||
);
|
|
||||||
|
|
||||||
let randomRequestCount = Math.floor(Math.random() * 10);
|
|
||||||
|
|
||||||
for (randomRequestCount; randomRequestCount > 0; randomRequestCount--) {
|
|
||||||
workerChannel.put({
|
|
||||||
responseData: {
|
|
||||||
test: randomRequestCount,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
expect(mockRequestChannel.put).toBeCalledWith({
|
|
||||||
requestData: {
|
|
||||||
test: randomRequestCount,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
workerChannel.put({
|
|
||||||
responseData: {
|
|
||||||
finished: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(mockResponseChannel.put).toBeCalledWith({ finished: true });
|
|
||||||
|
|
||||||
expect(mockRequestChannel.close).toBeCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
test("duplex response channel handler", async () => {
|
test("duplex response channel handler", async () => {
|
||||||
const w = new GracefulWorkerService(MockWorker);
|
const w = new GracefulWorkerService(MockWorker);
|
||||||
await runSaga({}, w.start);
|
await runSaga({}, w.start);
|
||||||
|
|
@ -294,42 +245,27 @@ describe("GracefulWorkerService", () => {
|
||||||
expect(MockWorker.instance).toBeDefined();
|
expect(MockWorker.instance).toBeDefined();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const mockChannel = (name = "mock") => ({
|
const mainThreadResponseChannel = channel();
|
||||||
name,
|
|
||||||
take: jest.fn(),
|
|
||||||
put: jest.fn(),
|
|
||||||
flush: jest.fn(),
|
|
||||||
close: jest.fn(),
|
|
||||||
});
|
|
||||||
const mockWorkerChannel = mockChannel("worker");
|
|
||||||
const responseChannel = channel();
|
|
||||||
const workerRequestId = "testID";
|
const workerRequestId = "testID";
|
||||||
runSaga(
|
runSaga(
|
||||||
{},
|
{},
|
||||||
// @ts-expect-error: type mismatch
|
// @ts-expect-error: type mismatch
|
||||||
w.duplexResponseHandler,
|
w.duplexResponseHandler,
|
||||||
workerRequestId,
|
mainThreadResponseChannel,
|
||||||
mockWorkerChannel,
|
|
||||||
responseChannel,
|
|
||||||
);
|
);
|
||||||
MockWorker.instance.postMessage = jest.fn();
|
MockWorker.instance.postMessage = jest.fn();
|
||||||
|
|
||||||
let randomRequestCount = Math.floor(Math.random() * 10);
|
let randomRequestCount = Math.floor(Math.random() * 10);
|
||||||
|
|
||||||
for (randomRequestCount; randomRequestCount > 0; randomRequestCount--) {
|
for (randomRequestCount; randomRequestCount > 0; randomRequestCount--) {
|
||||||
responseChannel.put({
|
mainThreadResponseChannel.put({
|
||||||
test: randomRequestCount,
|
test: randomRequestCount,
|
||||||
|
requestId: workerRequestId,
|
||||||
});
|
});
|
||||||
expect(MockWorker.instance.postMessage).toBeCalledWith({
|
expect(MockWorker.instance.postMessage).toBeCalledWith({
|
||||||
test: randomRequestCount,
|
test: randomRequestCount,
|
||||||
requestId: workerRequestId,
|
requestId: workerRequestId,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
responseChannel.put({
|
|
||||||
finished: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(mockWorkerChannel.close).toBeCalled();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import { channel, Channel, buffers } from "redux-saga";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import log from "loglevel";
|
import log from "loglevel";
|
||||||
import WebpackWorker from "worker-loader!";
|
import WebpackWorker from "worker-loader!";
|
||||||
|
// import { executeDynamicTriggerRequest } from "sagas/EvaluationsSaga";
|
||||||
/**
|
/**
|
||||||
* Wrap a webworker to provide a synchronous request-response semantic.
|
* Wrap a webworker to provide a synchronous request-response semantic.
|
||||||
*
|
*
|
||||||
|
|
@ -50,13 +51,15 @@ export class GracefulWorkerService {
|
||||||
|
|
||||||
private readonly _workerClass: typeof WebpackWorker;
|
private readonly _workerClass: typeof WebpackWorker;
|
||||||
|
|
||||||
|
public mainThreadRequestChannel: Channel<any>;
|
||||||
|
public mainThreadResponseChannel: Channel<any>;
|
||||||
|
|
||||||
constructor(workerClass: typeof WebpackWorker) {
|
constructor(workerClass: typeof WebpackWorker) {
|
||||||
this.shutdown = this.shutdown.bind(this);
|
this.shutdown = this.shutdown.bind(this);
|
||||||
this.start = this.start.bind(this);
|
this.start = this.start.bind(this);
|
||||||
this.request = this.request.bind(this);
|
this.request = this.request.bind(this);
|
||||||
this._broker = this._broker.bind(this);
|
this._broker = this._broker.bind(this);
|
||||||
this.duplexRequest = this.duplexRequest.bind(this);
|
this.duplexRequest = this.duplexRequest.bind(this);
|
||||||
this.duplexRequestHandler = this.duplexRequestHandler.bind(this);
|
|
||||||
this.duplexResponseHandler = this.duplexResponseHandler.bind(this);
|
this.duplexResponseHandler = this.duplexResponseHandler.bind(this);
|
||||||
|
|
||||||
// Do not buffer messages on this channel
|
// Do not buffer messages on this channel
|
||||||
|
|
@ -64,6 +67,8 @@ export class GracefulWorkerService {
|
||||||
this._isReady = false;
|
this._isReady = false;
|
||||||
this._channels = new Map<string, Channel<any>>();
|
this._channels = new Map<string, Channel<any>>();
|
||||||
this._workerClass = workerClass;
|
this._workerClass = workerClass;
|
||||||
|
this.mainThreadRequestChannel = channel();
|
||||||
|
this.mainThreadResponseChannel = channel();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -77,6 +82,10 @@ export class GracefulWorkerService {
|
||||||
// Inform all pending requests that we're good to go!
|
// Inform all pending requests that we're good to go!
|
||||||
this._isReady = true;
|
this._isReady = true;
|
||||||
yield put(this._readyChan, true);
|
yield put(this._readyChan, true);
|
||||||
|
yield spawn(this.duplexResponseHandler, this.mainThreadResponseChannel);
|
||||||
|
return {
|
||||||
|
mainThreadRequestChannel: this.mainThreadRequestChannel,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -96,6 +105,8 @@ export class GracefulWorkerService {
|
||||||
this._evaluationWorker.removeEventListener("message", this._broker);
|
this._evaluationWorker.removeEventListener("message", this._broker);
|
||||||
this._evaluationWorker.terminate();
|
this._evaluationWorker.terminate();
|
||||||
this._evaluationWorker = undefined;
|
this._evaluationWorker = undefined;
|
||||||
|
this.mainThreadRequestChannel.close();
|
||||||
|
this.mainThreadResponseChannel.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -182,29 +193,8 @@ export class GracefulWorkerService {
|
||||||
const workerRequestId = `${method}__${_.uniqueId()}`;
|
const workerRequestId = `${method}__${_.uniqueId()}`;
|
||||||
// The worker channel is the main channel
|
// The worker channel is the main channel
|
||||||
// where the web worker messages will get posted
|
// where the web worker messages will get posted
|
||||||
const workerChannel = channel();
|
const isFinishedChannel = channel();
|
||||||
this._channels.set(workerRequestId, workerChannel);
|
this._channels.set(workerRequestId, isFinishedChannel);
|
||||||
// The main thread will listen to the
|
|
||||||
// request channel where it will get worker messages
|
|
||||||
const mainThreadRequestChannel = channel();
|
|
||||||
// The main thread will respond back on the
|
|
||||||
// response channel which will be relayed to the worker
|
|
||||||
const mainThreadResponseChannel = channel();
|
|
||||||
|
|
||||||
// We spawn both the main thread request and response handler
|
|
||||||
yield spawn(
|
|
||||||
this.duplexRequestHandler,
|
|
||||||
workerChannel,
|
|
||||||
mainThreadRequestChannel,
|
|
||||||
mainThreadResponseChannel,
|
|
||||||
);
|
|
||||||
yield spawn(
|
|
||||||
this.duplexResponseHandler,
|
|
||||||
workerRequestId,
|
|
||||||
workerChannel,
|
|
||||||
mainThreadResponseChannel,
|
|
||||||
);
|
|
||||||
|
|
||||||
// And post the first message to the worker
|
// And post the first message to the worker
|
||||||
this._evaluationWorker.postMessage({
|
this._evaluationWorker.postMessage({
|
||||||
method,
|
method,
|
||||||
|
|
@ -214,75 +204,27 @@ export class GracefulWorkerService {
|
||||||
|
|
||||||
// Returning these channels to the main thread so that they can listen and post on it
|
// Returning these channels to the main thread so that they can listen and post on it
|
||||||
return {
|
return {
|
||||||
responseChannel: mainThreadResponseChannel,
|
isFinishedChannel: isFinishedChannel,
|
||||||
requestChannel: mainThreadRequestChannel,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
*duplexRequestHandler(
|
*duplexResponseHandler(mainThreadResponseChannel: Channel<any>) {
|
||||||
workerChannel: Channel<any>,
|
|
||||||
requestChannel: Channel<any>,
|
|
||||||
responseChannel: Channel<any>,
|
|
||||||
) {
|
|
||||||
if (!this._evaluationWorker) return;
|
if (!this._evaluationWorker) return;
|
||||||
try {
|
try {
|
||||||
let keepAlive = true;
|
const keepAlive = true;
|
||||||
while (keepAlive) {
|
|
||||||
// Wait for a message from the worker
|
|
||||||
const workerResponse: {
|
|
||||||
responseData: {
|
|
||||||
finished: unknown;
|
|
||||||
};
|
|
||||||
} = yield take(workerChannel);
|
|
||||||
const { responseData } = workerResponse;
|
|
||||||
// post that message to the request channel so the main thread can read it
|
|
||||||
requestChannel.put({ requestData: responseData });
|
|
||||||
// If we get a finished flag, the worker is requesting to end the request
|
|
||||||
if (responseData.finished) {
|
|
||||||
keepAlive = false;
|
|
||||||
// Relay the finished flag to the response channel as well
|
|
||||||
responseChannel.put({
|
|
||||||
finished: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
log.error(e);
|
|
||||||
} finally {
|
|
||||||
// Cleanup
|
|
||||||
requestChannel.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
*duplexResponseHandler(
|
|
||||||
workerRequestId: string,
|
|
||||||
workerChannel: Channel<any>,
|
|
||||||
responseChannel: Channel<any>,
|
|
||||||
) {
|
|
||||||
if (!this._evaluationWorker) return;
|
|
||||||
try {
|
|
||||||
let keepAlive = true;
|
|
||||||
while (keepAlive) {
|
while (keepAlive) {
|
||||||
// Wait for the main thread to respond back after a request
|
// Wait for the main thread to respond back after a request
|
||||||
const response: { finished: unknown } = yield take(responseChannel);
|
const response: { finished: unknown; requestId: string } = yield take(
|
||||||
// If we get a finished flag, the worker is requesting to end the request
|
mainThreadResponseChannel,
|
||||||
if (response.finished) {
|
);
|
||||||
keepAlive = false;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// send response to worker
|
// send response to worker
|
||||||
this._evaluationWorker.postMessage({
|
this._evaluationWorker.postMessage({
|
||||||
...response,
|
...response,
|
||||||
requestId: workerRequestId,
|
requestId: response.requestId,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log.error(e);
|
log.error(e);
|
||||||
} finally {
|
|
||||||
// clean up everything
|
|
||||||
responseChannel.close();
|
|
||||||
workerChannel.close();
|
|
||||||
this._channels.delete(workerRequestId);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -290,12 +232,28 @@ export class GracefulWorkerService {
|
||||||
if (!event || !event.data) {
|
if (!event || !event.data) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const { requestId, responseData, timeTaken } = event.data;
|
const { promisified, requestId, responseData, timeTaken } = event.data;
|
||||||
const ch = this._channels.get(requestId);
|
const ch = this._channels.get(requestId);
|
||||||
// Channel could have been deleted if the request gets cancelled before the WebWorker can respond.
|
// Channel could have been deleted if the request gets cancelled before the WebWorker can respond.
|
||||||
// In that case, we want to drop the request.
|
// In that case, we want to drop the request.
|
||||||
if (ch) {
|
if (promisified) {
|
||||||
ch.put({ responseData, timeTaken });
|
if (responseData.finished) {
|
||||||
|
if (ch) {
|
||||||
|
ch.put({ requestData: responseData, timeTaken, requestId });
|
||||||
|
this._channels.delete(requestId);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.mainThreadRequestChannel.put({
|
||||||
|
requestData: responseData,
|
||||||
|
timeTaken,
|
||||||
|
requestId,
|
||||||
|
mainThreadResponseChannel: this.mainThreadResponseChannel,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (ch) {
|
||||||
|
ch.put({ responseData, timeTaken, requestId });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -122,6 +122,7 @@ describe("Add functions", () => {
|
||||||
expect(workerEventMock).lastCalledWith({
|
expect(workerEventMock).lastCalledWith({
|
||||||
type: "PROCESS_TRIGGER",
|
type: "PROCESS_TRIGGER",
|
||||||
requestId: "EVAL_TRIGGER",
|
requestId: "EVAL_TRIGGER",
|
||||||
|
promisified: true,
|
||||||
responseData: {
|
responseData: {
|
||||||
errors: [],
|
errors: [],
|
||||||
subRequestId: expect.stringContaining("EVAL_TRIGGER_"),
|
subRequestId: expect.stringContaining("EVAL_TRIGGER_"),
|
||||||
|
|
@ -142,6 +143,7 @@ describe("Add functions", () => {
|
||||||
expect(workerEventMock).lastCalledWith({
|
expect(workerEventMock).lastCalledWith({
|
||||||
type: "PROCESS_TRIGGER",
|
type: "PROCESS_TRIGGER",
|
||||||
requestId: "EVAL_TRIGGER",
|
requestId: "EVAL_TRIGGER",
|
||||||
|
promisified: true,
|
||||||
responseData: {
|
responseData: {
|
||||||
errors: [],
|
errors: [],
|
||||||
subRequestId: expect.stringContaining("EVAL_TRIGGER_"),
|
subRequestId: expect.stringContaining("EVAL_TRIGGER_"),
|
||||||
|
|
@ -165,6 +167,7 @@ describe("Add functions", () => {
|
||||||
expect(workerEventMock).lastCalledWith({
|
expect(workerEventMock).lastCalledWith({
|
||||||
type: "PROCESS_TRIGGER",
|
type: "PROCESS_TRIGGER",
|
||||||
requestId: "EVAL_TRIGGER",
|
requestId: "EVAL_TRIGGER",
|
||||||
|
promisified: true,
|
||||||
responseData: {
|
responseData: {
|
||||||
errors: [],
|
errors: [],
|
||||||
subRequestId: expect.stringContaining("EVAL_TRIGGER_"),
|
subRequestId: expect.stringContaining("EVAL_TRIGGER_"),
|
||||||
|
|
@ -183,6 +186,7 @@ describe("Add functions", () => {
|
||||||
expect(workerEventMock).lastCalledWith({
|
expect(workerEventMock).lastCalledWith({
|
||||||
type: "PROCESS_TRIGGER",
|
type: "PROCESS_TRIGGER",
|
||||||
requestId: "EVAL_TRIGGER",
|
requestId: "EVAL_TRIGGER",
|
||||||
|
promisified: true,
|
||||||
responseData: {
|
responseData: {
|
||||||
errors: [],
|
errors: [],
|
||||||
subRequestId: expect.stringContaining("EVAL_TRIGGER_"),
|
subRequestId: expect.stringContaining("EVAL_TRIGGER_"),
|
||||||
|
|
@ -202,6 +206,7 @@ describe("Add functions", () => {
|
||||||
expect(workerEventMock).lastCalledWith({
|
expect(workerEventMock).lastCalledWith({
|
||||||
type: "PROCESS_TRIGGER",
|
type: "PROCESS_TRIGGER",
|
||||||
requestId: "EVAL_TRIGGER",
|
requestId: "EVAL_TRIGGER",
|
||||||
|
promisified: true,
|
||||||
responseData: {
|
responseData: {
|
||||||
errors: [],
|
errors: [],
|
||||||
subRequestId: expect.stringContaining("EVAL_TRIGGER_"),
|
subRequestId: expect.stringContaining("EVAL_TRIGGER_"),
|
||||||
|
|
@ -227,6 +232,7 @@ describe("Add functions", () => {
|
||||||
expect(workerEventMock).lastCalledWith({
|
expect(workerEventMock).lastCalledWith({
|
||||||
type: "PROCESS_TRIGGER",
|
type: "PROCESS_TRIGGER",
|
||||||
requestId: "EVAL_TRIGGER",
|
requestId: "EVAL_TRIGGER",
|
||||||
|
promisified: true,
|
||||||
responseData: {
|
responseData: {
|
||||||
errors: [],
|
errors: [],
|
||||||
subRequestId: expect.stringContaining("EVAL_TRIGGER_"),
|
subRequestId: expect.stringContaining("EVAL_TRIGGER_"),
|
||||||
|
|
@ -249,6 +255,7 @@ describe("Add functions", () => {
|
||||||
expect(workerEventMock).lastCalledWith({
|
expect(workerEventMock).lastCalledWith({
|
||||||
type: "PROCESS_TRIGGER",
|
type: "PROCESS_TRIGGER",
|
||||||
requestId: "EVAL_TRIGGER",
|
requestId: "EVAL_TRIGGER",
|
||||||
|
promisified: true,
|
||||||
responseData: {
|
responseData: {
|
||||||
errors: [],
|
errors: [],
|
||||||
subRequestId: expect.stringContaining("EVAL_TRIGGER_"),
|
subRequestId: expect.stringContaining("EVAL_TRIGGER_"),
|
||||||
|
|
@ -270,6 +277,7 @@ describe("Add functions", () => {
|
||||||
expect(workerEventMock).lastCalledWith({
|
expect(workerEventMock).lastCalledWith({
|
||||||
type: "PROCESS_TRIGGER",
|
type: "PROCESS_TRIGGER",
|
||||||
requestId: "EVAL_TRIGGER",
|
requestId: "EVAL_TRIGGER",
|
||||||
|
promisified: true,
|
||||||
responseData: {
|
responseData: {
|
||||||
errors: [],
|
errors: [],
|
||||||
subRequestId: expect.stringContaining("EVAL_TRIGGER_"),
|
subRequestId: expect.stringContaining("EVAL_TRIGGER_"),
|
||||||
|
|
@ -289,6 +297,7 @@ describe("Add functions", () => {
|
||||||
expect(workerEventMock).lastCalledWith({
|
expect(workerEventMock).lastCalledWith({
|
||||||
type: "PROCESS_TRIGGER",
|
type: "PROCESS_TRIGGER",
|
||||||
requestId: "EVAL_TRIGGER",
|
requestId: "EVAL_TRIGGER",
|
||||||
|
promisified: true,
|
||||||
responseData: {
|
responseData: {
|
||||||
errors: [],
|
errors: [],
|
||||||
subRequestId: expect.stringContaining("EVAL_TRIGGER_"),
|
subRequestId: expect.stringContaining("EVAL_TRIGGER_"),
|
||||||
|
|
@ -317,6 +326,7 @@ describe("Add functions", () => {
|
||||||
expect(workerEventMock).lastCalledWith({
|
expect(workerEventMock).lastCalledWith({
|
||||||
type: "PROCESS_TRIGGER",
|
type: "PROCESS_TRIGGER",
|
||||||
requestId: "EVAL_TRIGGER",
|
requestId: "EVAL_TRIGGER",
|
||||||
|
promisified: true,
|
||||||
responseData: {
|
responseData: {
|
||||||
errors: [],
|
errors: [],
|
||||||
subRequestId: expect.stringContaining("EVAL_TRIGGER_"),
|
subRequestId: expect.stringContaining("EVAL_TRIGGER_"),
|
||||||
|
|
@ -342,6 +352,7 @@ describe("Add functions", () => {
|
||||||
expect(workerEventMock).lastCalledWith({
|
expect(workerEventMock).lastCalledWith({
|
||||||
type: "PROCESS_TRIGGER",
|
type: "PROCESS_TRIGGER",
|
||||||
requestId: "EVAL_TRIGGER",
|
requestId: "EVAL_TRIGGER",
|
||||||
|
promisified: true,
|
||||||
responseData: {
|
responseData: {
|
||||||
errors: [],
|
errors: [],
|
||||||
subRequestId: expect.stringContaining("EVAL_TRIGGER_"),
|
subRequestId: expect.stringContaining("EVAL_TRIGGER_"),
|
||||||
|
|
@ -363,6 +374,7 @@ describe("Add functions", () => {
|
||||||
expect(workerEventMock).lastCalledWith({
|
expect(workerEventMock).lastCalledWith({
|
||||||
type: "PROCESS_TRIGGER",
|
type: "PROCESS_TRIGGER",
|
||||||
requestId: "EVAL_TRIGGER",
|
requestId: "EVAL_TRIGGER",
|
||||||
|
promisified: true,
|
||||||
responseData: {
|
responseData: {
|
||||||
errors: [],
|
errors: [],
|
||||||
subRequestId: expect.stringContaining("EVAL_TRIGGER_"),
|
subRequestId: expect.stringContaining("EVAL_TRIGGER_"),
|
||||||
|
|
@ -387,6 +399,7 @@ describe("Add functions", () => {
|
||||||
expect(workerEventMock).lastCalledWith({
|
expect(workerEventMock).lastCalledWith({
|
||||||
type: "PROCESS_TRIGGER",
|
type: "PROCESS_TRIGGER",
|
||||||
requestId: "EVAL_TRIGGER",
|
requestId: "EVAL_TRIGGER",
|
||||||
|
promisified: true,
|
||||||
responseData: {
|
responseData: {
|
||||||
errors: [],
|
errors: [],
|
||||||
subRequestId: expect.stringContaining("EVAL_TRIGGER_"),
|
subRequestId: expect.stringContaining("EVAL_TRIGGER_"),
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ describe("promise execution", () => {
|
||||||
expect(postMessageMock).toBeCalledWith({
|
expect(postMessageMock).toBeCalledWith({
|
||||||
requestId,
|
requestId,
|
||||||
type: "PROCESS_TRIGGER",
|
type: "PROCESS_TRIGGER",
|
||||||
|
promisified: true,
|
||||||
responseData: expect.objectContaining({
|
responseData: expect.objectContaining({
|
||||||
subRequestId: expect.stringContaining(`${requestId}_`),
|
subRequestId: expect.stringContaining(`${requestId}_`),
|
||||||
trigger: {
|
trigger: {
|
||||||
|
|
@ -116,6 +117,7 @@ describe("promise execution", () => {
|
||||||
method: "PROCESS_TRIGGER",
|
method: "PROCESS_TRIGGER",
|
||||||
requestId,
|
requestId,
|
||||||
success: true,
|
success: true,
|
||||||
|
promisified: true,
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
@ -153,6 +155,7 @@ describe("promise execution", () => {
|
||||||
method: "PROCESS_TRIGGER",
|
method: "PROCESS_TRIGGER",
|
||||||
requestId,
|
requestId,
|
||||||
success: true,
|
success: true,
|
||||||
|
promisified: true,
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
@ -164,6 +167,7 @@ describe("promise execution", () => {
|
||||||
method: "PROCESS_TRIGGER",
|
method: "PROCESS_TRIGGER",
|
||||||
requestId,
|
requestId,
|
||||||
success: false,
|
success: false,
|
||||||
|
promisified: true,
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,7 @@ export const promisifyAction = (
|
||||||
type: EVAL_WORKER_ACTIONS.PROCESS_TRIGGER,
|
type: EVAL_WORKER_ACTIONS.PROCESS_TRIGGER,
|
||||||
responseData,
|
responseData,
|
||||||
requestId: workerRequestIdCopy,
|
requestId: workerRequestIdCopy,
|
||||||
|
promisified: true,
|
||||||
});
|
});
|
||||||
const processResponse = function(event: MessageEvent) {
|
const processResponse = function(event: MessageEvent) {
|
||||||
const { data, method, requestId, success } = event.data;
|
const { data, method, requestId, success } = event.data;
|
||||||
|
|
@ -99,6 +100,7 @@ export const completePromise = (requestId: string, result: EvalResult) => {
|
||||||
result,
|
result,
|
||||||
},
|
},
|
||||||
requestId,
|
requestId,
|
||||||
|
promisified: true,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -195,6 +195,7 @@ describe("evaluateAsync", () => {
|
||||||
await evaluateAsync(js, {}, "TEST_REQUEST", {});
|
await evaluateAsync(js, {}, "TEST_REQUEST", {});
|
||||||
expect(self.postMessage).toBeCalledWith({
|
expect(self.postMessage).toBeCalledWith({
|
||||||
requestId: "TEST_REQUEST",
|
requestId: "TEST_REQUEST",
|
||||||
|
promisified: true,
|
||||||
responseData: {
|
responseData: {
|
||||||
finished: true,
|
finished: true,
|
||||||
result: { errors: [], logs: [], result: 123, triggers: [] },
|
result: { errors: [], logs: [], result: 123, triggers: [] },
|
||||||
|
|
@ -209,6 +210,7 @@ describe("evaluateAsync", () => {
|
||||||
await evaluateAsync(js, {}, "TEST_REQUEST_1", {});
|
await evaluateAsync(js, {}, "TEST_REQUEST_1", {});
|
||||||
expect(self.postMessage).toBeCalledWith({
|
expect(self.postMessage).toBeCalledWith({
|
||||||
requestId: "TEST_REQUEST_1",
|
requestId: "TEST_REQUEST_1",
|
||||||
|
promisified: true,
|
||||||
responseData: {
|
responseData: {
|
||||||
finished: true,
|
finished: true,
|
||||||
result: {
|
result: {
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,21 @@ export const EvaluationScripts: Record<EvaluationScriptType, string> = {
|
||||||
`,
|
`,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const topLevelWorkerAPIs = Object.keys(self).reduce((acc, key: string) => {
|
||||||
|
acc[key] = true;
|
||||||
|
return acc;
|
||||||
|
}, {} as any);
|
||||||
|
|
||||||
|
function resetWorkerGlobalScope() {
|
||||||
|
for (const key of Object.keys(self)) {
|
||||||
|
if (topLevelWorkerAPIs[key]) continue;
|
||||||
|
if (key === "evaluationVersion") continue;
|
||||||
|
if (extraLibraries.find((lib) => lib.accessor === key)) continue;
|
||||||
|
// @ts-expect-error: Types are not available
|
||||||
|
delete self[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export const getScriptType = (
|
export const getScriptType = (
|
||||||
evalArgumentsExist = false,
|
evalArgumentsExist = false,
|
||||||
isTriggerBased = false,
|
isTriggerBased = false,
|
||||||
|
|
@ -232,6 +247,7 @@ export default function evaluateSync(
|
||||||
skipLogsOperations = false,
|
skipLogsOperations = false,
|
||||||
): EvalResult {
|
): EvalResult {
|
||||||
return (function() {
|
return (function() {
|
||||||
|
resetWorkerGlobalScope();
|
||||||
const errors: EvaluationError[] = [];
|
const errors: EvaluationError[] = [];
|
||||||
let logs: LogObject[] = [];
|
let logs: LogObject[] = [];
|
||||||
let result;
|
let result;
|
||||||
|
|
@ -305,6 +321,7 @@ export async function evaluateAsync(
|
||||||
evalArguments?: Array<any>,
|
evalArguments?: Array<any>,
|
||||||
) {
|
) {
|
||||||
return (async function() {
|
return (async function() {
|
||||||
|
resetWorkerGlobalScope();
|
||||||
const errors: EvaluationError[] = [];
|
const errors: EvaluationError[] = [];
|
||||||
let result;
|
let result;
|
||||||
let logs;
|
let logs;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user