Skip to content

Commit

Permalink
chore(simulator): simplify inclusive gateway join logic
Browse files Browse the repository at this point in the history
  • Loading branch information
nikku committed Nov 29, 2023
1 parent 335da42 commit f3775bd
Showing 1 changed file with 56 additions and 47 deletions.
103 changes: 56 additions & 47 deletions lib/simulator/behaviors/InclusiveGatewayBehavior.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,7 @@ export default function InclusiveGatewayBehavior(
}

InclusiveGatewayBehavior.prototype.enter = function(context) {

// join right away if possible
if (this._canJoin(context)) {
this._join(context);
return;
}

// join when all reachable tokens exit
// do not subscribe if a token of current parent scope is already waiting
const elementScopes = this._getElementScopes(context);
if (elementScopes.length > 1) {
return;
}

this._joinWhenPossible(context);
this._tryJoin(context);
};

InclusiveGatewayBehavior.prototype.exit = function(context) {
Expand Down Expand Up @@ -69,44 +55,47 @@ InclusiveGatewayBehavior.prototype.exit = function(context) {

};

/**
* Returns true if there are either no remaining scopes in the parent scope, or if they are not
* reachable from the current element.
*
* @returns {Boolean}
*/
InclusiveGatewayBehavior.prototype._canJoin = function(context) {
InclusiveGatewayBehavior.prototype._tryJoin = function(context) {

const remainingScopes = this._getRemainingScopes(context);

// there are still some tokens to wait for
if (remainingScopes.length && this._canReachAnyScope(remainingScopes, context.element)) {
return false;
const remainingElements = remainingScopes.map(scope => scope.element);

// join right away if possible
// this implies that there are no remaining scopes
// or non of the remaining scopes are reachable
if (!this._canReachAnyElement(remainingElements, context.element)) {
return this._join(context);
}

return true;
};
const elementScopes = this._getElementScopes(context);

InclusiveGatewayBehavior.prototype._joinWhenPossible = function(context) {
const {
scope
} = context;
const remainingScopes = this._getRemainingScopes(context);

// only subscribe to changes with the first
// element scope; prevent unneeded computation
if (elementScopes[0] !== scope) {
return;
}

const event = this._simulator.waitForScopes(scope, remainingScopes);

const subscription = this._simulator.subscribe(scope, event, () => {
subscription.remove();

if (this._canJoin(context)) {
this._join(context);
} else {

// resubscribe to wait for remaining scopes
this._joinWhenPossible(context);
}
this._tryJoin(context);
});
};

/**
* Get scopes that may potentially be waited for,
* in the context of an inclusive gateway.
*
* @param {object} context
* @return {object[]}
*/
InclusiveGatewayBehavior.prototype._getRemainingScopes = function(context) {
const {
scope,
Expand All @@ -117,8 +106,9 @@ InclusiveGatewayBehavior.prototype._getRemainingScopes = function(context) {
parent: parentScope
} = scope;

return this._simulator.findScopes(scope => (
scope.parent === parentScope && scope.element !== element));
return this._simulator.findScopes(
scope => scope.parent === parentScope && scope.element !== element
);
};

InclusiveGatewayBehavior.prototype._join = function(context) {
Expand All @@ -136,6 +126,13 @@ InclusiveGatewayBehavior.prototype._join = function(context) {
this._simulator.exit(context);
};

/**
* Get scopes on the element for the given context.
*
* @param {object} context
*
* @return {object[]} scopes
*/
InclusiveGatewayBehavior.prototype._getElementScopes = function(context) {
const {
element,
Expand All @@ -148,26 +145,42 @@ InclusiveGatewayBehavior.prototype._getElementScopes = function(context) {
});
};

InclusiveGatewayBehavior.prototype._canReachAnyScope = function(scopes, currentElement, traversed = new Set()) {
/**
* Return true if any elements can be reached
* from the current element, searching the execution
* graph backwards.
*
* @param {object[]} elements
* @param {object} currentElement
* @param {Set<object>} traversed
*
* @return {boolean}
*/
InclusiveGatewayBehavior.prototype._canReachAnyElement = function(elements, currentElement, traversed = new Set()) {

if (!elements.length) {
return false;
}

// avoid infinite recursion
if (traversed.has(currentElement)) {
return false;
}

traversed.add(currentElement);

if (anyScopeIsOnElement(scopes, currentElement)) {
if (elements.some(e => e === currentElement)) {
return true;
}

if (isSequenceFlow(currentElement)) {
return this._canReachAnyScope(scopes, currentElement.source, traversed);
return this._canReachAnyElement(elements, currentElement.source, traversed);
}

const incomingFlows = filterSequenceFlows(currentElement.incoming);

for (const flow of incomingFlows) {
if (this._canReachAnyScope(scopes, flow, traversed)) {
if (this._canReachAnyElement(elements, flow, traversed)) {
return true;
}
}
Expand All @@ -178,8 +191,4 @@ InclusiveGatewayBehavior.prototype._canReachAnyScope = function(scopes, currentE
InclusiveGatewayBehavior.$inject = [
'simulator',
'activityBehavior'
];

function anyScopeIsOnElement(scopes, element) {
return scopes.some(scope => scope.element === element);
}
];

0 comments on commit f3775bd

Please sign in to comment.