Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Resuming an engine seems to lose services #33

Closed
petermorlion opened this issue Feb 1, 2023 · 2 comments
Closed

Resuming an engine seems to lose services #33

petermorlion opened this issue Feb 1, 2023 · 2 comments

Comments

@petermorlion
Copy link

I'm looking for a way to configure a fairly complex flow behind a HTML form submission. The flow is hard-coded now but for our customers, we want to make it configurable. I'm making a POC but am stumbling on the user tasks. What I want is an Express app that uses the BPMN to navigate through the screens.

This is a simple BPMN I have now:

<?xml version="1.0" encoding="UTF-8"?>
<definitions id="testProcess" xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <process id="theProcess1" isExecutable="true">
    <startEvent id="theStart" />
    <userTask id="loginPage" />
    <exclusiveGateway id="checkLogin" />
    <serviceTask id="invalidLogin" implementation="{environment.service.invalidLogin}" />
    <serviceTask id="validLogin" implementation="{environment.service.validLogin}" />

    <sequenceFlow id="flow1" sourceRef="theStart" targetRef="loginPage" />
    <sequenceFlow id="flow2" sourceRef="loginPage" targetRef="checkLogin" />
    <sequenceFlow id="flow3a" sourceRef="checkLogin" targetRef="invalidLogin">
        <conditionExpression xsi:type="tFormalExpression">\${environment.services.isFalse(environment.variables.isValidLogin)}</conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="flow3b" sourceRef="checkLogin" targetRef="validLogin">
        <conditionExpression xsi:type="tFormalExpression">\${environment.services.isTrue(environment.variables.isValidLogin)}</conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="flow4" sourceRef="validLogin" targetRef="end1" />
    <sequenceFlow id="flow5" sourceRef="invalidLogin" targetRef="end2" />

    <endEvent id="end1" />
    <endEvent id="end2" />
  </process>
</definitions>

When I GET the root URL, my app starts the engine:

app.get('/', async (req, res) => {
    const id = Math.floor(Math.random() * 10000);
    engine = new Engine({
        name: 'execution example',
        source,
        variables: {
            id
        },
        listener,
        services: {
            req,
            res,
            isTrue: (val) => val === true,
            isFalse: (va) => val === false
        }
    });

    await engine.execute();
});

The listener listens to several events, but this is the important one:

listener.on('activity.wait', async (api, execution) => {
    if (api.type === "bpmn:UserTask") {
        await userTasks[api.id](api);
    }

    api.stop();
    state = await execution.getState();
});

The userTasks[api.id](api) basically calls the following logic:

function loginPage(api, execution) {
    api.environment.services.res.render('login');
}

Now this works on the GET. The state is stored and the engine is stopped. But when I POST the form, I want to continue the flow where I left off:

app.post('/', async (req, res) => {
    engine = new Engine().recover(state);
    
    await engine.resume({
        listener,
        variables: {
            isValidLogin: true
        },
        services: {
            req,
            res,
            isTrue: (val) => val === true,
            isFalse: (va) => val === false
        }
    })
});

First I was thinking it would take the correct flow after the loginPage task, but it seems it continues inside the loginPage task. Makes sense, as I haven't ended that activity yet.

So I was going to inspect the request object which I pass to the services option. However, on resuming my engine, I see that all services are undefined (req, res, isTrue and `isFalse).

What is the correct way to resume an engine and include the necessary services again so I can continue "as if nothing happened"?

@petermorlion
Copy link
Author

If this should be moved to the bpmn-engine repository, let me know and I'll recreate there. I realized I may have used the wrong repo.

@petermorlion
Copy link
Author

For anyone looking at this (including the author): I finally managed to achieve what I wanted. You can see my current POC here. For this specifically, I declared my services outside my Express handlers.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant