Skip to content

Commit b27ede8

Browse files
committed
Merge branch 'main' into usertask-matching-prototype
2 parents 3d7570a + 726ebab commit b27ede8

File tree

103 files changed

+4262
-2304
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

103 files changed

+4262
-2304
lines changed

docker-compose.research.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,14 @@ services:
1414
- proceed-network
1515

1616
proceed_research_postgres_database:
17-
image: postgres:latest
17+
image: postgres:17.7
1818
container_name: proceed_research_postgres_database
1919
env_file: .env.research
2020
restart: always
2121
ports:
2222
- '5433:5432'
2323
volumes:
24-
- proceed_research_postgres_db:/var/lib/postgresql
24+
- proceed_research_postgres_db:/var/lib/postgresql/data
2525
networks:
2626
- proceed-network
2727

docker-compose.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,22 +23,24 @@ services:
2323
- proceed-standalone-network
2424

2525
proceed_standalone_postgres_database:
26-
image: postgres:latest
26+
image: postgres:17.7
2727
container_name: proceed_standalone_postgres_database
2828
restart: unless-stopped
2929
environment:
3030
POSTGRES_DB: proceed_db
3131
POSTGRES_USER: proceed
3232
POSTGRES_PASSWORD: proceed
3333
volumes:
34-
- proceed_standalone_postgres_db:/var/lib/postgresql
34+
- proceed_standalone_postgres_db:/var/lib/postgresql/data
3535
networks:
3636
- proceed-standalone-network
3737

3838
proceed_standalone_engine:
3939
image: proceed/engine:edge
4040
container_name: proceed_standalone_engine
4141
restart: unless-stopped
42+
ports:
43+
- '33029:33029'
4244
networks:
4345
- proceed-standalone-network
4446

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,10 @@
5858
"docker:build-ms-standalone": "docker build -t proceed/ms-server:standalone -f ./src/management-system-v2/Dockerfile-selfhost .",
5959
"test": "yarn test-engine",
6060
"test-engine": "cross-env USE_PROJECTS=\"capabilities helper-modules engine-unit-integration\" jest",
61-
"test-ms": "cd src/management-system && yarn test:unit",
6261
"test-e2e": "cross-env USE_PROJECTS=\"engine-e2e\" jest src/engine/e2e_tests --runInBand --detectOpenHandles --forceExit",
62+
"test-ms": "cd src/management-system && yarn test:unit",
63+
"test-ms-e2e-prepare-server": "yarn dev-ms-db && yarn build-ms && yarn next start src/management-system-v2",
64+
"test-ms-e2e-start-playwright": "PLAYWRIGHT_TEST_BASE_URL='http://localhost:3000' yarn playwright test --ui",
6365
"test-all": "yarn test-engine && yarn test-e2e",
6466
"jsdoc": "jsdoc -c ./jsdoc.config.json --pedantic",
6567
"android-prepare": "cd src/engine/universal && webpack --output-path ../native/android/app/src/main/assets --config webpack.universal.config.js",

src/engine/e2e_tests/process/deployment/deployment.e2e.test.js

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3806,15 +3806,20 @@ describe('Test deploying a process', () => {
38063806
{
38073807
tokenId: expect.any(String),
38083808
state: 'PAUSED',
3809-
currentFlowElementId: 'Flow_1t4tcmh',
3809+
currentFlowElementId: 'Activity_1m0u15u',
38103810
currentFlowElementStartTime: expect.any(Number),
3811-
previousFlowElementId: 'Activity_1m0u15u',
3811+
previousFlowElementId: 'Flow_0n4ueli',
3812+
currentFlowNodeProgress: {
3813+
manual: false,
3814+
value: expect.any(Number),
3815+
},
3816+
currentFlowNodeState: 'ACTIVE',
38123817
localStartTime: expect.any(Number),
38133818
localExecutionTime: expect.any(Number),
38143819
machineHops: 0,
38153820
deciderStorageRounds: 0,
38163821
deciderStorageTime: 0,
3817-
intermediateVariablesState: null,
3822+
intermediateVariablesState: expect.any(Object),
38183823
},
38193824
]);
38203825
expect(instanceInfo.log).toEqual([
@@ -3831,20 +3836,6 @@ describe('Test deploying a process', () => {
38313836
port: 33020,
38323837
},
38333838
},
3834-
{
3835-
tokenId: expect.any(String),
3836-
flowElementId: 'Activity_1m0u15u',
3837-
executionState: 'COMPLETED',
3838-
startTime: expect.any(Number),
3839-
endTime: expect.any(Number),
3840-
machine: {
3841-
id: 'machineId1',
3842-
ip: expect.any(String),
3843-
name: 'machine1',
3844-
port: 33020,
3845-
},
3846-
progress: { value: 100, manual: false },
3847-
},
38483839
]);
38493840

38503841
expect(instanceInfo.adaptationLog).toEqual([]);

src/engine/native/node/native-script-execution/src/child-process/bpmn-errors.js

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,25 @@ module.exports = {
1919
`,
2020
);
2121
},
22-
/** @param {string} script */
23-
wrapScriptWithErrorHandling: function (script) {
24-
return `try {
22+
/**
23+
* @param {string} script
24+
* @param {string} [finallyCode]
25+
* */
26+
wrapScriptWithErrorHandling: function (script, finallyCode) {
27+
let code = `try {
2528
${script}
2629
} catch(e){
2730
if(${errorClasses.map((error) => 'e instanceof ' + error).join(' || ')})
2831
throw JSON.stringify(e);
2932
else throw e;
30-
}
31-
`;
33+
}`;
34+
35+
if (finallyCode) {
36+
code += `finally {
37+
${finallyCode}
38+
}`;
39+
}
40+
41+
return code;
3242
},
3343
};

src/engine/native/node/native-script-execution/src/child-process/http-server.js

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,17 @@ let listeningOn = {
1919
};
2020

2121
/** @param {import('.').ScriptTaskSetupData} setupData */
22-
module.exports = function setupNetworkServer({ context }) {
22+
module.exports = function setupNetworkServer({ context, waitUntilResumed }) {
2323
let listenerAdded = false;
24+
/** @param {any} message */
2425
async function ipcMessageHandler(message) {
2526
try {
2627
// TODO: check structure of message
2728

2829
if (message.type !== 'http-request') return;
2930

31+
await waitUntilResumed();
32+
3033
const method = message.request.method.toLowerCase();
3134
const listeners = listeningOn[method];
3235

@@ -237,8 +240,8 @@ module.exports = function setupNetworkServer({ context }) {
237240
delete: new Map(),
238241
get: new Map(),
239242
};
240-
${_networkServerCall.toString()}; globalThis['_networkServerCall'] = _networkServerCall;
241-
${_processRequest.toString()}; globalThis['_processRequest'] = _processRequest;
243+
${_networkServerCall.toString()};
244+
${_processRequest.toString()};
242245
${_registerListener.toString()}
243246
${_Response.toString()}
244247
${_oneOffListener.toString()}
@@ -247,6 +250,17 @@ module.exports = function setupNetworkServer({ context }) {
247250
const $removeRoute = $2;
248251
const $removeIPCListener = $3;
249252
const $sendResponse = $4;
253+
254+
const _networkServer = new Proxy(
255+
{},
256+
{
257+
get: function (_, method) {
258+
return (...args) => _networkServerCall(method, args);
259+
},
260+
},
261+
);
262+
263+
globalThis["networkServer"] = _networkServer;
250264
`,
251265
[
252266
new ivm.Reference((method, path) => {

src/engine/native/node/native-script-execution/src/child-process/index.js

Lines changed: 44 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -25,37 +25,6 @@ if (
2525
'Expected the following args processId, processInstanceId, tokenId, scriptString, token',
2626
);
2727

28-
/* -------------------------------------------------------------------------------------------------
29-
* Basic isolated vm setup
30-
* -----------------------------------------------------------------------------------------------*/
31-
32-
const isolate = new ivm.Isolate({ memoryLimit: 128 });
33-
const context = isolate.createContextSync();
34-
35-
context.global.setSync('global', context.global.derefInto());
36-
37-
context.global.setSync('_stdout_log', function (...args) {
38-
console.log(...args);
39-
});
40-
41-
const wait = new ivm.Reference((ms) => new Promise((res) => setTimeout(res, ms)));
42-
43-
context.evalClosureSync(
44-
function wait(ms) {
45-
$0.applySyncPromise(null, [ms], {});
46-
}.toString() + `globalThis["wait"] = wait;`,
47-
[wait],
48-
);
49-
50-
context.evalClosureSync(
51-
async function waitAsync(ms) {
52-
await $0.apply(null, [ms], {
53-
result: { promise: true },
54-
});
55-
}.toString() + `globalThis["waitAsync"] = waitAsync;`,
56-
[wait],
57-
);
58-
5928
/* -------------------------------------------------------------------------------------------------
6029
* Function for communication with universal part
6130
* -----------------------------------------------------------------------------------------------*/
@@ -107,6 +76,19 @@ async function callToExecutor(endpoint, body) {
10776
}
10877
}
10978

79+
/* -------------------------------------------------------------------------------------------------
80+
* Basic isolated vm setup
81+
* -----------------------------------------------------------------------------------------------*/
82+
83+
const isolate = new ivm.Isolate({ memoryLimit: 128 });
84+
const context = isolate.createContextSync();
85+
86+
context.global.setSync('global', context.global.derefInto());
87+
88+
context.global.setSync('_stdout_log', function (...args) {
89+
console.log(...args);
90+
});
91+
11092
/* -------------------------------------------------------------------------------------------------
11193
* Setup PROCEED's api for script task
11294
*
@@ -125,6 +107,7 @@ async function callToExecutor(endpoint, body) {
125107
* processId: string,
126108
* processInstanceId: string,
127109
* tokenId: string
110+
* waitUntilResumed: () => Promise<void>
128111
* }} ScriptTaskSetupData
129112
*/
130113

@@ -135,8 +118,34 @@ const setupData = {
135118
processId,
136119
processInstanceId,
137120
tokenId,
121+
waitUntilResumed: () => Promise.resolve(),
138122
};
139123

124+
const setupPauseAndResumeLayer = require('./pause-resume-layer');
125+
const { waitUntilResumed, unmountPauseResumeListener } = setupPauseAndResumeLayer(setupData);
126+
setupData.waitUntilResumed = waitUntilResumed;
127+
128+
const wait = new ivm.Reference(async (ms) => {
129+
await new Promise((res) => setTimeout(res, ms));
130+
await waitUntilResumed();
131+
});
132+
133+
context.evalClosureSync(
134+
function wait(ms) {
135+
$0.applySyncPromise(null, [ms], {});
136+
}.toString() + `globalThis["wait"] = wait;`,
137+
[wait],
138+
);
139+
140+
context.evalClosureSync(
141+
async function waitAsync(ms) {
142+
await $0.apply(null, [ms], {
143+
result: { promise: true },
144+
});
145+
}.toString() + `globalThis["waitAsync"] = waitAsync;`,
146+
[wait],
147+
);
148+
140149
const setupSimpleFunctionCalls = require('./simple-function-calls');
141150
setupSimpleFunctionCalls(setupData);
142151

@@ -156,11 +165,14 @@ setupNetworkServer(setupData);
156165
* Execute script
157166
* -----------------------------------------------------------------------------------------------*/
158167

168+
/** @param {string} script */
159169
function wrapScriptInAsyncFunction(script) {
160170
return `async function main() { ${script} }; main();`;
161171
}
162172

163-
const isolateCode = wrapScriptInAsyncFunction(wrapScriptWithErrorHandling(scriptString));
173+
const isolateCode = wrapScriptInAsyncFunction(
174+
wrapScriptWithErrorHandling(scriptString, unmountPauseResumeListener),
175+
);
164176

165177
// After .eval is done, there may still be code running inside the isolate, that the .eval returns
166178
// means just that the code the user wrote returned a value, the process will remain open until the
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// @ts-check
2+
3+
const ivm = require('isolated-vm');
4+
5+
const pauseMessageType = 'pause-execution';
6+
const resumeMessageType = 'resume-execution';
7+
8+
/** @param {Omit<import('.').ScriptTaskSetupData, "waitUntilResumed">} setupData */
9+
module.exports = function setupPauseAndResumeLayer({ context }) {
10+
/** @typedef {{
11+
* promise: Promise<void>;
12+
* resolve: () => void;
13+
* reject: () => void;
14+
* }} PausePromise */
15+
16+
/** @type { PausePromise | undefined } */
17+
let executionPausedPromise = undefined;
18+
19+
/** @param {any} message */
20+
function ipcMessageHandler(message) {
21+
try {
22+
// TODO: check structure of message
23+
24+
if (message.type === pauseMessageType) {
25+
/** @type { PausePromise } */
26+
const pausePromise = {};
27+
pausePromise.promise = new Promise((res, rej) => {
28+
pausePromise.resolve = res;
29+
pausePromise.reject = rej;
30+
});
31+
32+
executionPausedPromise = pausePromise;
33+
} else if (message.type === resumeMessageType && executionPausedPromise) {
34+
executionPausedPromise.resolve();
35+
executionPausedPromise = undefined;
36+
}
37+
} catch (e) {
38+
console.error('Error pausing/resuming execution', e);
39+
}
40+
}
41+
process.on('message', ipcMessageHandler);
42+
43+
context.evalClosure("globalThis['_unmountPauseListener'] = function() { $0.apply(null, []) }", [
44+
new ivm.Reference(() => {
45+
// If this listener isn't removed, the childProcess will not end after the evaluation of
46+
// the script task is done
47+
48+
process.removeListener('message', ipcMessageHandler);
49+
}),
50+
]);
51+
52+
return {
53+
async waitUntilResumed() {
54+
if (executionPausedPromise) {
55+
await executionPausedPromise.promise;
56+
}
57+
},
58+
unmountPauseResumeListener: '\n_unmountPauseListener();',
59+
};
60+
};

src/engine/native/node/native-script-execution/src/child-process/service-calls.js

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,14 @@ module.exports = function setupServiceCalls({
99
processId,
1010
processInstanceId,
1111
tokenId,
12+
waitUntilResumed,
1213
}) {
1314
/** @param {string} serviceName */
1415
function _getService(serviceName) {
1516
return new Proxy(
1617
{},
1718
{
1819
get: function (_, method) {
19-
// network-server is a bit more complex so it requires it's own implementation
20-
// _networkServerCall is defined in ./http-server.js
21-
if (serviceName === 'network-server') {
22-
return (...args) => _networkServerCall(method, args);
23-
}
24-
2520
return (...args) => _callToService(serviceName, method, args);
2621
},
2722
},
@@ -72,6 +67,7 @@ module.exports = function setupServiceCalls({
7267
${_parseResult.toString()};
7368
${_callToService.toString()};
7469
${_getService.toString()}; globalThis["getService"] = _getService;
70+
globalThis["networkRequest"] = getService("network-requests");
7571
`,
7672
[
7773
new ivm.Reference(
@@ -81,6 +77,7 @@ module.exports = function setupServiceCalls({
8177
* @param {string} args stringified array of args
8278
*/
8379
async function (serviceName, method, args) {
80+
await waitUntilResumed();
8481
const result = await callToExecutor('call', {
8582
functionName: `getService.${serviceName}.${method}`,
8683
args: [processId, processInstanceId, tokenId, ...JSON.parse(args)],

0 commit comments

Comments
 (0)