[NodeJS] Abort workflow execution if client's HTTP request is aborted

I want the following PHP functionality into NodeJS:

<?php
ignore_user_abort(false); // Abort script execution if HTTP request aborted

ExpressJS, how to detect if client aborted the HTTP request:

app.get('/', function(req, res){
    req.on('close', function(){
        req.isDisconnected = true // I made this variable name, don't know if it's ok to set it like that
    });
});

On method exec of lib/modules/core.js, you could check the boolean req.isDisconnected before proceeding with the execution of the step, what do you think @patrick?

I didn’t know the ignore_user_abort function in PHP. But it seems to have a flaw, from the Notes in the documentation: PHP will not detect that the user has aborted the connection until an attempt is made to send information to the client.. Since we only send content to the client after the action finished it will not abort.

On NodeJS it could work, but you could get some unwanted behavior if you don’t handle it well. Perhaps we could throw an error if the user disconnects so that you can still catch it and do some database rollback or other actions that are required.

Interesting discovery of the PHP flaw.

Will do this as a custom extension for the time being. Can you just confirm what’s the best method to access req.isDisconnected inside a custom extension? this.req.isDisconnected would work? Or how do you suggest to pass the variable?

True. I was also thinking about a situation a while ago while helping a user: if we entered an infinite loop (infinite condition) we could stop such execution by just aborting the browser request, that’s why I initially mentioned doing the check at exec as that’s pretty sure to be called anywhere I guess

P.S.: Don’t forget to answer my question (in the 2nd paragraph)

I think the request object is a good place to store the isDisconnected flag. Implementing it in a custom extension will be difficult, we don’t have any hooks which you can use to check before each action execution, the exec method in lib/modules/core.js is only an action step. The real execution method is in lib/core/app.js, at line 487 it is calling the actual action method.

I’m already investigating for the implementation for the different server models. The idea is to have it as an extra server option which you can enable (disabled by default for not changing the current behavior). I then check before each action execution if it is still connected and throw an error if not. I think we will implement this very soon.

While you’re at it, you can also abort in-progress API Action (HTTP client) calls:

// lib/modules/api.js 
this.req.on('close', function(){ // this.req.on for incoming HTTP request (user -> server)
    req.abort() // req for HTTP client (server -> 3rd party API)
    // Need to check what happens if you call req.abort() on a already finished request (hopefully it doesn't throw an error)
});

Reference:

Also, take in consideration scheduled actions don’t have a this.req object (I guess), so req.on would probably throw an error in those cases due to being undefined or null, a check would probably be needed before using the .on method

Instead of req.on(“close”), you can use a req.on("_wappler_close") so that you can freely toggle those events depending on user preferences

Here the changes I made:

lib/server.js: server.zip (1.1 KB)
lib/setup/config.js: config.zip (955 Bytes)
lib/core/app.js: app.zip (4.3 KB)

To enable it you can add "abortOnDisconnect": true to api/config/config.json or change the value in config.js to true.

If it throws an error, doesn’t anything that goes inside the Catch will throw the error as well? Perhaps I would suggest making use of a counter variable, to only throw once

Your right, it should not throw again when in a catch.

Meanwhile, feel free to push your current code into Beta, works for me as it is. It throws an error in console when a request is aborted (“Got error?”) but it doesn’t impact functionality

With this updated file it should not throw an error in the catch.

app.zip (4.3 KB)

Hi Patrick,

I’m implementing API Action abortion:

            if (this.config.abortOnDisconnect) {
                this.req.on('close', function() { // this.req.on for incoming HTTP request (user -> server)
                    req.destroy()
                })
            }

The problem is this.config doesn’t exist - how can I get the configuration inside lib/modules/api.js?

There’s a getOAuthProvider method - could we make the same for getConfig?

Just leaving a note here regarding the current implementation of req.isDisconnected

It seems there’s some odd behaviour with req.on(‘close’), sometimes HTTP requests get aborted for no meaningful reason, but this doesn’t happen with the deprecated req.on(‘abort’)