Skip to content

Commit

Permalink
allow activity to be discarded pending resume
Browse files Browse the repository at this point in the history
fix cancelled spelling
  • Loading branch information
paed01 committed Jul 13, 2023
1 parent 60e8f14 commit 4d1dd8d
Show file tree
Hide file tree
Showing 17 changed files with 299 additions and 36 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ Refactor scripts again

# 2.1.0

Transactions and compensation if canceled.
Transactions and compensation if cancelled.

## Additions
- Add support for Transaction
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ The following elements are tested and supported.
- SignalEventDefinition
- throw
- catch
- SignalTask
- [SignalTask](/docs/SignalTask.md)
- ManualTask
- UserTask
- [StandardLoopCharacteristics](/docs/LoopCharacteristics.md)
Expand Down
11 changes: 10 additions & 1 deletion dist/definition/DefinitionExecution.js
Original file line number Diff line number Diff line change
Expand Up @@ -602,7 +602,16 @@ DefinitionExecution.prototype._onCancelCallActivity = function onCancelCallActiv
const targetProcess = this.getProcessByExecutionId(bpExecutionId);
if (!targetProcess) return;
this._debug(`cancel call from <${fromParent.id}.${fromId}> to <${calledElement}>`);
targetProcess.getApi().discard();
if (!targetProcess.isRunning) {
targetProcess.getApi({
content: {
id: targetProcess.id,
executionId: targetProcess.executionId
}
}).discard();
} else {
targetProcess.getApi().discard();
}
};
DefinitionExecution.prototype._onDelegateMessage = function onDelegateMessage(routingKey, executeMessage) {
const content = executeMessage.content;
Expand Down
25 changes: 20 additions & 5 deletions dist/events/BoundaryEvent.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,13 +107,28 @@ BoundaryEventBehaviour.prototype._onCompleted = function onCompleted(_, {
}));
}
this[kCompleteContent] = content;
const inbound = this[kExecuteMessage].content.inbound;
const {
inbound,
executionId
} = this[kExecuteMessage].content;
const attachedToContent = inbound && inbound[0];
const attachedTo = this.attachedTo;
this.activity.logger.debug(`<${this.executionId} (${this.id})> cancel ${attachedTo.status} activity <${attachedToContent.executionId} (${attachedToContent.id})>`);
attachedTo.getApi({
content: attachedToContent
}).discard();
this.activity.logger.debug(`<${executionId} (${this.id})> cancel ${attachedTo.status} activity <${attachedToContent.executionId} (${attachedToContent.id})>`);
if (content.isRecovered && !attachedTo.isRunning) {
const attachedExecuteTag = `_on-attached-execute-${executionId}`;
this[kAttachedTags].push(attachedExecuteTag);
attachedTo.broker.subscribeOnce('execution', '#', () => {
attachedTo.getApi({
content: attachedToContent
}).discard();
}, {
consumerTag: attachedExecuteTag
});
} else {
attachedTo.getApi({
content: attachedToContent
}).discard();
}
};
BoundaryEventBehaviour.prototype._onAttachedLeave = function onAttachedLeave(_, {
content
Expand Down
4 changes: 4 additions & 0 deletions docs/SharedApi.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ Arguments:
- `options`: optional object with broker message options
- `delegate`: optional boolean to delegate the signal to all interested parties

### `fail(error)`

Fail activity with error. The purpose is to fail user-/signal tasks waiting for user input. The behaviour differs between different type of activities.

### `stop()`

Stop element run. Publishes stop message on element broker `api` exchange.
Expand Down
55 changes: 55 additions & 0 deletions docs/SignalTask.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
SignalTask
===========

Signal-/User-/Manual task behaviour.

```javascript
import * as elements from 'bpmn-elements';

import BpmnModdle from 'bpmn-moddle';

import {default as serialize, TypeResolver} from 'moddle-context-serializer';

const {Context, Definition} = elements;
const typeResolver = TypeResolver(elements);

const source = `
<?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="theProcess" isExecutable="true">
<userTask id="task" name="Wait for user input" />
</process>
</definitions>`;

(async () => {
const def = await run();
const [userTask] = def.getPostponed();

userTask.fail(new Error('Custom errror'));
})();

async function run() {
const moddleContext = await getModdleContext(source);
const options = {
Logger,
};
const context = new Context(serialize(moddleContext, typeResolver));

const definition = new Definition(context, options);
definition.run();
return definition;
}

function getModdleContext(sourceXml) {
const bpmnModdle = new BpmnModdle();
return bpmnModdle.fromXML(sourceXml.trim());
}

function Logger(scope) {
return {
debug: console.debug.bind(console, 'bpmn-elements:' + scope),
error: console.error.bind(console, 'bpmn-elements:' + scope),
warn: console.warn.bind(console, 'bpmn-elements:' + scope),
};
}
```
4 changes: 2 additions & 2 deletions docs/TimerEventDefinition.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Object with properties. A subset:

## `activity.timeout`

Fired when the timer has timed out or was canceled.
Fired when the timer has timed out or was cancelled.

Object with `activity.timer` properties and some:

Expand All @@ -42,7 +42,7 @@ Behaves the same as `timeDuration`. Due date will timeout immediately. An invali

Default support for ISO8601 repeating interval.

If another format is used, e.g. cron, the event definition will wait until canceled. There are several modules to handle time cycles and this project tries to keep the number of dependencies to a minimum.
If another format is used, e.g. cron, the event definition will wait until cancelled. There are several modules to handle time cycles and this project tries to keep the number of dependencies to a minimum.

# Combined `timeDuration` and `timeDate`

Expand Down
10 changes: 5 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "bpmn-elements",
"version": "11.1.0",
"version": "11.1.1",
"description": "Executable workflow elements based on BPMN 2.0",
"type": "module",
"main": "dist/index.js",
Expand Down Expand Up @@ -45,9 +45,9 @@
],
"devDependencies": {
"@aircall/expression-parser": "^1.0.4",
"@babel/cli": "^7.22.5",
"@babel/core": "^7.22.5",
"@babel/preset-env": "^7.22.5",
"@babel/cli": "^7.22.9",
"@babel/core": "^7.22.9",
"@babel/preset-env": "^7.22.9",
"@babel/register": "^7.22.5",
"@bonniernews/hot-bev": "^0.4.0",
"bpmn-moddle": "^8.0.1",
Expand All @@ -56,7 +56,7 @@
"chai": "^4.3.7",
"chronokinesis": "^5.0.2",
"debug": "^4.3.4",
"eslint": "^8.43.0",
"eslint": "^8.44.0",
"eslint-plugin-import": "^2.27.5",
"got": "^12.6.1",
"mocha": "^10.1.0",
Expand Down
11 changes: 10 additions & 1 deletion src/definition/DefinitionExecution.js
Original file line number Diff line number Diff line change
Expand Up @@ -614,7 +614,16 @@ DefinitionExecution.prototype._onCancelCallActivity = function onCancelCallActiv

this._debug(`cancel call from <${fromParent.id}.${fromId}> to <${calledElement}>`);

targetProcess.getApi().discard();
if (!targetProcess.isRunning) {
targetProcess.getApi({
content: {
id: targetProcess.id,
executionId: targetProcess.executionId,
},
}).discard();
} else {
targetProcess.getApi().discard();
}
};

DefinitionExecution.prototype._onDelegateMessage = function onDelegateMessage(routingKey, executeMessage) {
Expand Down
14 changes: 11 additions & 3 deletions src/events/BoundaryEvent.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,13 +103,21 @@ BoundaryEventBehaviour.prototype._onCompleted = function onCompleted(_, {content

this[kCompleteContent] = content;

const inbound = this[kExecuteMessage].content.inbound;
const {inbound, executionId} = this[kExecuteMessage].content;
const attachedToContent = inbound && inbound[0];
const attachedTo = this.attachedTo;

this.activity.logger.debug(`<${this.executionId} (${this.id})> cancel ${attachedTo.status} activity <${attachedToContent.executionId} (${attachedToContent.id})>`);
this.activity.logger.debug(`<${executionId} (${this.id})> cancel ${attachedTo.status} activity <${attachedToContent.executionId} (${attachedToContent.id})>`);

attachedTo.getApi({content: attachedToContent}).discard();
if (content.isRecovered && !attachedTo.isRunning) {
const attachedExecuteTag = `_on-attached-execute-${executionId}`;
this[kAttachedTags].push(attachedExecuteTag);
attachedTo.broker.subscribeOnce('execution', '#', () => {
attachedTo.getApi({content: attachedToContent}).discard();
}, {consumerTag: attachedExecuteTag});
} else {
attachedTo.getApi({content: attachedToContent}).discard();
}
};

BoundaryEventBehaviour.prototype._onAttachedLeave = function onAttachedLeave(_, {content}) {
Expand Down
2 changes: 1 addition & 1 deletion test/activity/ActivityExecution-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1517,7 +1517,7 @@ describe('ActivityExecution', () => {
}
});

it('last iteration canceled completes execution', () => {
it('last iteration cancelled completes execution', () => {
const task = createActivity(Behaviour);
const execution = new ActivityExecution(task);

Expand Down
4 changes: 2 additions & 2 deletions test/eventDefinitions/CancelEventDefinition-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ describe('CancelEventDefinition', () => {
expect(messages[0].content.parent).to.have.property('executionId', 'theProcess_0');
});

it('expects cancel with canceled routing key', () => {
it('expects cancel with cancelled routing key', () => {
const catchEvent = new CancelEventDefinition(event, {
type: 'bpmn:CancelEventDefinition',
});
Expand Down Expand Up @@ -168,7 +168,7 @@ describe('CancelEventDefinition', () => {
},
});

event.broker.publish('execution', 'execute.canceled.event_1_0', {id: 'atomic', isTransaction: true});
event.broker.publish('execution', 'execute.cancelled.event_1_0', {id: 'atomic', isTransaction: true});
event.broker.publish('api', 'activity.stop.event_1', {}, {type: 'stop'});

expect(event.broker).to.have.property('consumerCount', 0);
Expand Down
12 changes: 6 additions & 6 deletions test/eventDefinitions/TimerEventDefinition-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -894,7 +894,7 @@ describe('TimerEventDefinition', () => {
ActivityApi(broker, timerMessage).discard();
});

it('can be canceled', (done) => {
it('can be cancelled', (done) => {
const definition = new TimerEventDefinition(event, {
type: 'bpmn:TimerEventDefinition',
behaviour: {
Expand Down Expand Up @@ -1097,7 +1097,7 @@ describe('TimerEventDefinition', () => {
after(ck.reset);

describe('cancel ' + descr, () => {
it('completes when parent is canceled', (done) => {
it('completes when parent is cancelled', (done) => {
const messages = [];
event.broker.subscribeTmp('event', 'activity.*', (_, msg) => {
messages.push(msg);
Expand All @@ -1124,7 +1124,7 @@ describe('TimerEventDefinition', () => {
ActivityApi(event.broker, messages[0]).cancel();
});

it('completes when parent is canceled on activity timer event', (done) => {
it('completes when parent is cancelled on activity timer event', (done) => {
event.broker.subscribeOnce('execution', 'execute.completed', () => {
done();
});
Expand All @@ -1146,7 +1146,7 @@ describe('TimerEventDefinition', () => {
});
});

it('completes if canceled on activity timer event', (done) => {
it('completes if cancelled on activity timer event', (done) => {
event.broker.subscribeTmp('event', 'activity.timer', (_, msg) => {
ActivityApi(event.broker, msg).cancel();
}, {noAck: true});
Expand All @@ -1168,7 +1168,7 @@ describe('TimerEventDefinition', () => {
});
});

it('completes when delegated a canceled with parent id', (done) => {
it('completes when delegated a cancelled with parent id', (done) => {
const messages = [];
event.broker.subscribeTmp('event', 'activity.timeout', (_, msg) => {
messages.push(msg);
Expand Down Expand Up @@ -1399,7 +1399,7 @@ describe('TimerEventDefinition', () => {
ActivityApi(broker, timerMessage).discard();
});

it('can be canceled', (done) => {
it('can be cancelled', (done) => {
const broker = event.broker;

let timerMessage;
Expand Down
2 changes: 1 addition & 1 deletion test/feature/EventBasedGateway-feature.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ Feature('EventBasedGateway', () => {
signalApi = await wait;
});

When('timer is canceled', () => {
When('timer is cancelled', () => {
bp.cancelActivity({id: timerApi.id});
});

Expand Down
Loading

0 comments on commit 4d1dd8d

Please sign in to comment.