0

I have express js server which listens for a request from a user:

// PUG template

$("#request").click(()=>{
  $.ajax({url: "/launch", method: 'get'});
})
// server.js

app.get('/launch', (req, res) => {
    getCatalog();
}

This should launch a huge do while function, which may literally work for hours, except if user wishes to cancel it.

Question: what should be the proper way to launch and cancel this function by user request?

// PUG template

$("#cancel").click(()=>{
  ...
})
ezik
  • 451
  • 1
  • 4
  • 15
  • Is getCatalog an async function? you could use promises on the server (inside getCatalog) and then have an endpoint that you call to cancel the promise. Cancellable promises aren't in ES6 so you may need to use something like Bluebird, check out this question https://stackoverflow.com/questions/29478751/cancel-a-vanilla-ecmascript-6-promise-chain – Grant Jul 11 '19 at 14:52
  • This would need to be a multi-part solution, and it would all depend on to what you mean by cancel? Do you want to just ignore the result from the client or do you want to _actually_ cancel the request? i.e. stop the server from doing what it's doing? Because that would involve you having to implement cancellation support at the backend. – James Jul 11 '19 at 14:55
  • @Grant, yes, it's async. – ezik Jul 12 '19 at 04:58
  • @James, by cancelling i mean break; in inside while. Express provides req.on('cancel'), if the window was closed, i used it like so: ` req.on('close', () => { return (isCancelled = true); }); ` ` if (isCancelled) { break; } ` But how to call this event emitter through user request? – ezik Jul 12 '19 at 04:59

2 Answers2

0

I would approach this case with code logic other than express functionality. You can create a class that handles catalog loading and also have a state for this process that you can turn on and off (I believe loading process involves multi async functions calls so the event loop allow this). For example:

class CatalogLoader {
    constructor() {
        this.isProcessing = false
    }

    getCatalog() {
        this.isProcessing = true
        while(... && this.isProcessing) {
            // Huge loading logic 
        }
                this.isProcessing = false
        }
}

And in express you can add below api:

app.get('/launch', (req, res) => {
    catalogLoader.getCatalog();
}

app.get('/cancelLaunch', (req, res) => {
    catalogLoader.isProcessing = false
    ...
}
Avi L
  • 1,558
  • 2
  • 15
  • 33
0

Second possible solution using require('child_process');, but you need to know the PID of the process you wish to cancel. Benefit: unload the main node thread from a heavy task.

So, including node's const childProcess = require('child_process');

Then:

app.get('/launch', (req,res) => {
    const getCatalog = childProcess.fork('script.js', null, {
        detached: true
    });
    res.send();
});

app.get('/kill', (req,res,next) => {
    const pid = req.query.pid;
    if (pid) {
        process.kill(pid);
        res.send();
    } else {
        res.end();
    }
});


$("#requestCancel").click(()=>{
  $.ajax({url: "/kill?pid=variable*", method: 'get'});
})
ezik
  • 451
  • 1
  • 4
  • 15