question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

infinity discard loop

See original GitHub issue

Hi, I’m not sure is this issue is the same with issues#73 which has been closed.

I’ve tried the same code with two diagram (source1 and source2), and encounter this issue with source2. The only difference between source1 and source2 is that source2 has ‘Task1’ which add one more loop-back to ‘Task2’.

Look into the log, I think there are 2 strange parts. First is, from line 2 in the log, the ‘Task2’ is be discarded two times with same execution id. It is expectable because both ‘Flow2’ and ‘FlowTrue1’ discarding Task2, but should not have same execution id. Second is, the second Flow3’s behavior, which is also triggered by discarding Task2 should also be discarded, but it didn’t. (3-lines above, the first Flow3 is discarded normally) log

here is my code:

'use strict';

const { Engine } = require('bpmn-engine');

const sleep = async (sec) => {
	return new Promise((resolve) => {
		setTimeout(resolve, sec * 1000);
	});
};

const services = {
	doTask1: async (scope, callback) => {
		scope.logger.debug(`##### doing doTask1 <${scope.content.executionId}>`);
		await sleep(1); // calling other heavy service...
		return callback(null);
	},
	doTask2: async (scope, callback) => {
		scope.logger.debug(`##### doing doTask2 <${scope.content.executionId}>`);
		await (async () => {
			await sleep(1); // calling other heavy service...
			scope.environment.variables.passTask2--;
		})();
		return callback(null);
	},
};

(async (source1, source2) => {
	const source = source2; // choice source here

	let engineState;

	const engine = Engine({
		source,
		services,
		variables: { passTask2: 1 },
		extensions: {
			listenUserTask: activity => {
				if (activity.id !== 'UserTask') return;
				activity.on('wait', async (api, context) => {
					// await (async () => {})(); // however, if I uncomment this line, source1 will become normal
					api.owner.logger.debug(`##### log state immediately in wait`);
					engineState = await engine.getState();
				});
			},
		},
	});

	// first execute
	await engine.execute();

	// sleep awhile then resume
	setTimeout(async () => {
		engine.logger.debug(`##### wakeup, resuming...`);

		const recoveredEngine = Engine({
			services,
		}).recover(engineState);

		const api = await recoveredEngine.resume({}, (err, execution) => {
			console.log('completed!!');
		});

		api.signal({ id: 'UserTask' });
	}, 5000);
})(`
<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="Definition_GeneralFlow" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="4.1.1">
  <bpmn:process id="Process_GeneralFlow" isExecutable="true">
    <bpmn:startEvent id="Start" name="Start">
      <bpmn:outgoing>Flow1</bpmn:outgoing>
    </bpmn:startEvent>
    <bpmn:endEvent id="End" name="End">
      <bpmn:incoming>FlowFalse2</bpmn:incoming>
      <bpmn:incoming>FlowLater</bpmn:incoming>
    </bpmn:endEvent>
    <bpmn:serviceTask id="Task2" name="Task2" implementation="\${environment.services.doTask2}">
      <bpmn:incoming>FlowTrue1</bpmn:incoming>
      <bpmn:incoming>Flow1</bpmn:incoming>
      <bpmn:outgoing>Flow3</bpmn:outgoing>
    </bpmn:serviceTask>
    <bpmn:userTask id="UserTask" name="UserTask">
      <bpmn:incoming>FlowFirst</bpmn:incoming>
      <bpmn:outgoing>Flow4</bpmn:outgoing>
    </bpmn:userTask>
    <bpmn:exclusiveGateway id="Gateway1" name="Gateway1">
      <bpmn:incoming>Flow3</bpmn:incoming>
      <bpmn:outgoing>FlowFirst</bpmn:outgoing>
      <bpmn:outgoing>FlowLater</bpmn:outgoing>
    </bpmn:exclusiveGateway>
    <bpmn:exclusiveGateway id="Gateway2" name="Gateway2">
      <bpmn:incoming>Flow4</bpmn:incoming>
      <bpmn:outgoing>FlowFalse2</bpmn:outgoing>
      <bpmn:outgoing>FlowTrue1</bpmn:outgoing>
    </bpmn:exclusiveGateway>
    <bpmn:sequenceFlow id="Flow1" name="Flow1" sourceRef="Start" targetRef="Task2" />
    <bpmn:sequenceFlow id="Flow3" name="Flow3" sourceRef="Task2" targetRef="Gateway1" />
    <bpmn:sequenceFlow id="Flow4" name="Flow4" sourceRef="UserTask" targetRef="Gateway2" />
    <bpmn:sequenceFlow id="FlowFirst" name="FlowFirst" sourceRef="Gateway1" targetRef="UserTask">
      <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression" language="javascript">this.environment.variables.passTask2&gt;=0</bpmn:conditionExpression>
    </bpmn:sequenceFlow>
    <bpmn:sequenceFlow id="FlowLater" name="FlowLater" sourceRef="Gateway1" targetRef="End">
      <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression" language="javascript">this.environment.variables.passTask2&lt;0</bpmn:conditionExpression>
    </bpmn:sequenceFlow>
    <bpmn:sequenceFlow id="FlowFalse2" name="FlowFalse2" sourceRef="Gateway2" targetRef="End">
      <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression" language="javascript">false</bpmn:conditionExpression>
    </bpmn:sequenceFlow>
    <bpmn:sequenceFlow id="FlowTrue1" name="FlowTrue1" sourceRef="Gateway2" targetRef="Task2">
      <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression" language="javascript">true</bpmn:conditionExpression>
    </bpmn:sequenceFlow>
  </bpmn:process>
</bpmn:definitions>`, `
<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="Definition_GeneralFlow" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="4.1.1">
  <bpmn:process id="Process_GeneralFlow" isExecutable="true">
    <bpmn:startEvent id="Start" name="Start">
      <bpmn:outgoing>Flow1</bpmn:outgoing>
    </bpmn:startEvent>
    <bpmn:endEvent id="End" name="End">
      <bpmn:incoming>FlowFalse2</bpmn:incoming>
      <bpmn:incoming>FlowLater</bpmn:incoming>
    </bpmn:endEvent>
    <bpmn:serviceTask id="Task1" name="Task1" implementation="\${environment.services.doTask1}">
      <bpmn:incoming>Flow1</bpmn:incoming>
      <bpmn:incoming>FlowFalse1</bpmn:incoming>
      <bpmn:outgoing>Flow2</bpmn:outgoing>
    </bpmn:serviceTask>
    <bpmn:serviceTask id="Task2" name="Task2" implementation="\${environment.services.doTask2}">
      <bpmn:incoming>Flow2</bpmn:incoming>
      <bpmn:incoming>FlowTrue1</bpmn:incoming>
      <bpmn:outgoing>Flow3</bpmn:outgoing>
    </bpmn:serviceTask>
    <bpmn:userTask id="UserTask" name="UserTask">
      <bpmn:incoming>FlowFirst</bpmn:incoming>
      <bpmn:outgoing>Flow4</bpmn:outgoing>
    </bpmn:userTask>
    <bpmn:exclusiveGateway id="Gateway1" name="Gateway1">
      <bpmn:incoming>Flow3</bpmn:incoming>
      <bpmn:outgoing>FlowFirst</bpmn:outgoing>
      <bpmn:outgoing>FlowLater</bpmn:outgoing>
    </bpmn:exclusiveGateway>
    <bpmn:exclusiveGateway id="Gateway2" name="Gateway2">
      <bpmn:incoming>Flow4</bpmn:incoming>
      <bpmn:outgoing>FlowFalse1</bpmn:outgoing>
      <bpmn:outgoing>FlowFalse2</bpmn:outgoing>
      <bpmn:outgoing>FlowTrue1</bpmn:outgoing>
    </bpmn:exclusiveGateway>
    <bpmn:sequenceFlow id="Flow1" name="Flow1" sourceRef="Start" targetRef="Task1" />
    <bpmn:sequenceFlow id="Flow2" name="Flow2" sourceRef="Task1" targetRef="Task2" />
    <bpmn:sequenceFlow id="Flow3" name="Flow3" sourceRef="Task2" targetRef="Gateway1" />
    <bpmn:sequenceFlow id="Flow4" name="Flow4" sourceRef="UserTask" targetRef="Gateway2" />
    <bpmn:sequenceFlow id="FlowFirst" name="FlowFirst" sourceRef="Gateway1" targetRef="UserTask">
      <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression" language="javascript">this.environment.variables.passTask2&gt;=0</bpmn:conditionExpression>
    </bpmn:sequenceFlow>
    <bpmn:sequenceFlow id="FlowLater" name="FlowLater" sourceRef="Gateway1" targetRef="End">
      <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression" language="javascript">this.environment.variables.passTask2&lt;0</bpmn:conditionExpression>
    </bpmn:sequenceFlow>
    <bpmn:sequenceFlow id="FlowFalse1" name="FlowFalse1" sourceRef="Gateway2" targetRef="Task1">
      <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression" language="javascript">false</bpmn:conditionExpression>
    </bpmn:sequenceFlow>
    <bpmn:sequenceFlow id="FlowFalse2" name="FlowFalse2" sourceRef="Gateway2" targetRef="End">
      <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression" language="javascript">false</bpmn:conditionExpression>
    </bpmn:sequenceFlow>
    <bpmn:sequenceFlow id="FlowTrue1" name="FlowTrue1" sourceRef="Gateway2" targetRef="Task2">
      <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression" language="javascript">true</bpmn:conditionExpression>
    </bpmn:sequenceFlow>
  </bpmn:process>
</bpmn:definitions>`);

source1’s diagram: source1

source2’s diagram: source2

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:8 (5 by maintainers)

github_iconTop GitHub Comments

1reaction
paed01commented, Aug 18, 2020

No problem. Thank you for making me aware of the bug.

If you consider this issue solved, please close it.

0reactions
aowakennomaicommented, Aug 18, 2020

Got it! Thank you very much 😃

Read more comments on GitHub >

github_iconTop Results From Across the Web

New inifinite loop! - BoardGameGeek
You can do an infinite with an empty deck/discard, premonition bell, and any "then draw a card" heroes in the middle row.
Read more >
Infinity damage loops :: Across the Obelisk General Discussions
But the real loop starts here. Since you have no cards in your draw or discard decks at all, and Warpaint is a...
Read more >
Infinite Combo | Slay the Spire Wiki - Fandom
The discard pile must contain a card, usually an Attack, that allows you to draw the multi-draw card again. ... Infinity: play 25...
Read more >
Top 10 Cards Which Cause Infinite Loops in YuGiOh - YouTube
This video was sponsored by Skillshare.Get 2 months of Skillshare free for the first 500 people to sign up at ...
Read more >
Discard Loop - Decks - Marvel Snap Zone
Discard Loop - Marvel Snap Decks, Guides, and More.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found