Skip to content

Commit

Permalink
add get timers endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
paed01 committed Jul 9, 2024
1 parent 45e618a commit f2507ec
Show file tree
Hide file tree
Showing 25 changed files with 354 additions and 101 deletions.
3 changes: 2 additions & 1 deletion .prettierrc.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"tabWidth": 2,
"printWidth": 140,
"singleQuote": true
"singleQuote": true,
"trailingComma": "es5"
}
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@

# Unreleased

## [0.3.0] - 2024-07-05
## [0.3.0] - 2024-07-09

- add `GET (*)?/timers/:deploymentName` endpoint to serve timers
- add new middleware option to disable auto-save state
- require storage adapter `update` function to update an existing entity. The function takes same arguments as `upsert` but will/should throw if the entity key was not found
- add default BPMN Engine service functions: `saveState`, `disableSaveState`, `enableSaveState`. The functions takes no arguments, at the moment
Expand Down
21 changes: 21 additions & 0 deletions docs/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ Returns Expressjs Router with extra properties:
- [`POST (*)?/deployment/create`](#post-deploymentcreate)
- [`POST (*)?/process-definition/:deploymentName/start`](#post-process-definitiondeploymentnamestart)
- [`GET (*)?/script/:deploymentName`](#get-scriptdeploymentname)
- [`GET (*)?/timers/:deploymentName`](#get-timersdeploymentname)
- [`GET (*)?/running`](#get-running)
- [`GET (*)?/status/:token`](#get-statustoken)
- [`GET (*)?/status/:token/:activityId`](#get-statustokenactivityid)
Expand Down Expand Up @@ -98,6 +99,26 @@ Response:
- `content-type: text/javascript`
- `body`: module script, exported javascript functions where function name non-word characters are replaced with `_`

### `GET (*)?/timers/:deploymentName`

Get all declared timers for deployment

Response:

- `timers`: list of timers
- `name`: timer name
- `parent`: timer parent element
- `id`: element id
- `type`: element type
- `timer`: timer element
- `timerType`: timer type
- `value`: timer string value
- `success`: boolean, true if successfully parsed
- `expireAt`: closest expire at datetime
- `delay`: number of milliseconds delay
- `repeat`: optional repeat number
- `message`: error message if not successfully parsed

### `GET (*)?/running`

Get all running instances.
Expand Down
2 changes: 1 addition & 1 deletion eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ const rules = {
'no-undef-init': 2,
'no-undef': 2,
'no-underscore-dangle': 0,
'no-unused-vars': 0,
'no-unused-vars': 2,
'no-unused-expressions': 2,
'no-use-before-define': 0,
'no-var': 2,
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@
"texample": "^0.0.5"
},
"dependencies": {
"lru-cache": "^10.0.0",
"lru-cache": "^11.0.0",
"multer": "^1.4.5-lts.1"
},
"peerDependencies": {
Expand Down
15 changes: 1 addition & 14 deletions rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,9 @@ const { module, main, dependencies, peerDependencies } = nodeRequire('./package.
const external = new Set(
['node:module', 'node:url', 'node:vm', 'node:events', 'node:crypto', 'node:path', 'node:url']
.concat(Object.keys(dependencies))
.concat(Object.keys(peerDependencies)),
.concat(Object.keys(peerDependencies))
);

// export default {
// input: './src/index.js',
// plugins: [commonjs({ sourceMap: false })],
// external: ['bpmn-engine', 'express', 'lru-cache', 'multer', 'node:crypto', 'node:fs', 'node:module', 'node:path'],
// output: [
// {
// file: 'dist/main.cjs',
// format: 'cjs',
// exports: 'named',
// },
// ],
// };

export default {
input: module,
plugins: [
Expand Down
5 changes: 2 additions & 3 deletions src/Engines.js
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,6 @@ Engines.prototype.getPostponed = async function getPostponed(token, listener) {
return {
token,
...api.content,
// @ts-ignore
executing: api.getExecuting()?.map((e) => ({ ...e.content })),
};
});
Expand Down Expand Up @@ -417,7 +416,7 @@ Engines.prototype._setupEngine = function setupEngine(engine) {
token: engineOptions.token,
deployment: engine.name,
},
},
}
);
}

Expand All @@ -430,7 +429,7 @@ Engines.prototype._setupEngine = function setupEngine(engine) {
else if (message.content.isRecovered) return;
engineOptions.sequenceNumber++;
},
{ noAck: true, consumerTag: 'sequence-listener' },
{ noAck: true, consumerTag: 'sequence-listener' }
);

engineBroker.assertExchange('state', 'topic', { durable: false, autoDelete: false });
Expand Down
1 change: 1 addition & 0 deletions src/MemoryAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ MemoryAdapter.prototype.upsert = function upsert(type, key, value, options) {
case STORAGE_TYPE_STATE: {
const current = this.storage.get(storageKey);
// @ts-ignore
// eslint-disable-next-line no-unused-vars
const { engine, ...saved } = current ? JSON.parse(current) : {};
this.storage.set(storageKey, JSON.stringify({ ...saved, ...value }), options);
break;
Expand Down
57 changes: 53 additions & 4 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,6 @@ export function bpmnEngineMiddleware(options) {
idleTimeout: DEFAULT_IDLE_TIMER,
autosaveEngineState: true,
...options,
// engineOptions: { ...options?.engineOptions },
// engineCache: options?.engineCache,
// broker: options?.broker,
});

const storage = new MulterAdapterStorage(adapter);
Expand All @@ -56,6 +53,7 @@ export function bpmnEngineMiddleware(options) {
router.post('(*)?/deployment/create', multer({ storage }).any(), middleware.create.bind(middleware));
router.post('(*)?/process-definition/:deploymentName/start', json(), middleware._addEngineLocals, middleware.start.bind(middleware));
router.get('(*)?/script/:deploymentName', middleware._addEngineLocals, middleware.getScript.bind(middleware));
router.get('(*)?/timers/:deploymentName', middleware.getDeploymentTimers.bind(middleware));
router.get('(*)?/running', middleware.getRunning.bind(middleware));
router.get('(*)?/status/:token', middleware.getStatusByToken.bind(middleware));
router.get('(*)?/status/:token/:activityId', middleware._addEngineLocals, middleware.getActivityStatus.bind(middleware));
Expand Down Expand Up @@ -216,7 +214,7 @@ BpmnEngineMiddleware.prototype.getScript = async function getScript(req, res, ne
const deployment = await this._getDeploymentByName(deploymentName);
const deploymentSource = await this.adapter.fetch(STORAGE_TYPE_FILE, deployment[0].path);

const engine = new MiddlewareEngine(deploymentName, { ...this.engineOptions, source: deploymentSource.content });
const engine = this.engines.createEngine({ name: deploymentName, source: deploymentSource.content });
const [definition] = await engine.getDefinitions();

let payload = `// ${deploymentName} scripts `;
Expand All @@ -236,6 +234,57 @@ export function ${slugify(deploymentName, script.name)}(excutionContext, next) {
}
};

/**
* Start deployment
* @param {import('express').Request<{deploymentName:string}>} req
* @param {import('express').Response<{timers:import('types').ParsedTimerResult[]}>} res
* @param {import('express').NextFunction} next
*/
BpmnEngineMiddleware.prototype.getDeploymentTimers = async function getDeploymentTimers(req, res, next) {
try {
const deploymentName = req.params.deploymentName;
const deployment = await this._getDeploymentByName(deploymentName);
const deploymentSource = await this.adapter.fetch(STORAGE_TYPE_FILE, deployment[0].path);

const engine = this.engines.createEngine({ name: deploymentName, source: deploymentSource.content });
const [definition] = await engine.getDefinitions();

const contextTimers = definition.context.definitionContext.getTimers();
/** @type {typeof import('bpmn-elements').TimerEventDefinition} */
const TimerEventDefinition = engine.options.elements.TimerEventDefinition;

/** @type {import('types').ParsedTimerResult[]} */
const result = [];

for (const timer of contextTimers) {
const parsedTimer = { ...timer, success: true };
result.push(parsedTimer);

const element =
timer.parent.type === 'bpmn:Process' ? definition.getProcessById(timer.parent.id) : definition.getActivityById(timer.parent.id);

const { timerType, value } = timer.timer;

try {
// @ts-ignore
const ted = new TimerEventDefinition(element, { [timerType]: value });

// @ts-ignore
const parsed = ted.parse(timerType, value);
Object.assign(parsedTimer, parsed);
} catch (/** @type {any} */ err) {
parsedTimer.success = false;
// @ts-ignore
parsedTimer.message = err.message;
}
}

return res.send({ timers: result });
} catch (err) {
next(err);
}
};

/**
* Get running engines
* @param {import('express').Request<import('types').StorageQuery>} req
Expand Down
32 changes: 16 additions & 16 deletions test/express-middleware-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ describe('express-middleware', () => {
</process>
</definitions>
`,
'test-deploy-start.bpmn',
'test-deploy-start.bpmn'
);

await request(app).post('/rest/deployment/create').set(form.getHeaders()).send(form.getBuffer().toString()).expect(201);
Expand Down Expand Up @@ -231,7 +231,7 @@ describe('express-middleware', () => {
</serviceTask>
</process>
</definitions>`,
`${deploymentName}.bpmn`,
`${deploymentName}.bpmn`
);

await request(app).post('/rest/deployment/create').set(form.getHeaders()).send(form.getBuffer().toString()).expect(201);
Expand Down Expand Up @@ -297,7 +297,7 @@ describe('express-middleware', () => {
</serviceTask>
</process>
</definitions>`,
`${deploymentName}.bpmn`,
`${deploymentName}.bpmn`
);

await request(app).post('/rest/deployment/create').set(form.getHeaders()).send(form.getBuffer().toString()).expect(201);
Expand Down Expand Up @@ -349,7 +349,7 @@ describe('express-middleware', () => {
</process>
</definitions>
`,
`${deploymentName}.bpmn`,
`${deploymentName}.bpmn`
);

return request(app).post('/rest/deployment/create').set(form.getHeaders()).send(form.getBuffer().toString()).expect(201);
Expand Down Expand Up @@ -408,7 +408,7 @@ describe('express-middleware', () => {
</process>
</definitions>
`,
`${deploymentName}.bpmn`,
`${deploymentName}.bpmn`
);

return request(app).post('/rest/deployment/create').set(form.getHeaders()).send(form.getBuffer().toString()).expect(201);
Expand Down Expand Up @@ -451,7 +451,7 @@ describe('express-middleware', () => {
</process>
</definitions>
`,
`${deploymentName}.bpmn`,
`${deploymentName}.bpmn`
);

return request(app).post('/rest/deployment/create').set(form.getHeaders()).send(form.getBuffer().toString()).expect(201);
Expand Down Expand Up @@ -525,7 +525,7 @@ describe('express-middleware', () => {
</process>
</definitions>
`,
`${deploymentName}.bpmn`,
`${deploymentName}.bpmn`
);

return request(app).post('/rest/deployment/create').set(form.getHeaders()).send(form.getBuffer().toString()).expect(201);
Expand Down Expand Up @@ -578,7 +578,7 @@ describe('express-middleware', () => {
</process>
</definitions>
`,
`${deploymentName}.bpmn`,
`${deploymentName}.bpmn`
);

const errored = waitForProcess(app, deploymentName).error();
Expand Down Expand Up @@ -609,7 +609,7 @@ describe('express-middleware', () => {
</process>
</definitions>
`,
`${deploymentName}.bpmn`,
`${deploymentName}.bpmn`
);

await request(app).post('/rest/deployment/create').set(form.getHeaders()).send(form.getBuffer().toString()).expect(201);
Expand All @@ -636,14 +636,14 @@ describe('express-middleware', () => {
form.append(
`${deploymentName}.bpmn`,
`<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<process id="bp" isExecutable="true">
<scriptTask id="task" scriptFormat="javascript">
<script>next(new Error('Unexpected'));</script>
</process>
</definitions>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<process id="bp" isExecutable="true">
<scriptTask id="task" scriptFormat="javascript">
<script>next(new Error('Unexpected'));</script>
</process>
</definitions>
`,
`${deploymentName}.bpmn`,
`${deploymentName}.bpmn`
);

await request(app).post('/rest/deployment/create').set(form.getHeaders()).send(form.getBuffer().toString()).expect(201);
Expand Down
Loading

0 comments on commit f2507ec

Please sign in to comment.