Gherman
Gherman

Reputation: 7426

Is it possible to terminate a running web worker?

I have a web worker running a time-consuming routine task with ajax-requests. Can I terminate them from a main thread not waiting for them to finish?

That's how I spawn and terminate it:

$("button.parse-categories").click(function() {
    if (parseCategoriesActive==false) {
        parseCategoriesActive = true;
        parseCategoriesWorker = new Worker("parseCategories.js");


        $("button.parse-categories-cancel").click(function() {
            parseCategoriesWorker.terminate();
            parseCategoriesActive = false;
        });             
    }
});

This is the worker code:

function myAjax(url, async, callback) {
    xmlhttp = new XMLHttpRequest();
    xmlhttp.onreadystatechange=function() {
        if (xmlhttp.readyState==4 && xmlhttp.status==200)
            callback(xmlhttp.responseText);
        if (xmlhttp.readyState==4 && xmlhttp.status!=200) {
            self.postMessage("error");
            throw "error in ajax: "+xmlhttp.status;
        }
    }
    xmlhttp.open("GET", url, async);
    xmlhttp.send();
}

var parseCategoriesActive = true;
var counter = 0;
do {
    myAjax('parser.php', false, function(resp) {
        if (resp=='success')
            parseCategoriesActive = false;
        else {
            counter += Number(resp);
            self.postMessage(counter);
        }       
    });
} while (parseCategoriesActive==true);

Upvotes: 9

Views: 19017

Answers (3)

Birkensox
Birkensox

Reputation: 3721

The OP clearly asked:

Can I terminate them from a main thread not waiting for them to finish?

He is not asking how a worker should gracefully exit internally. He wants to very ungracefully kill any worker from an external thread.

  • You can kill any web worker by calling its terminate() function, assuming the worker instance is in context scope.

Web workers also have a life-cycle. They will self-terminate under specific conditions.

  • You can kill a dedicated worker by closing the page/frame that created it by calling window.close() from the main thread. That is what dedicated means - it is only allowed to serve a single page. Closing the page invokes the dedicated worker's self-termination sequence.

  • You can kill a shared worker by closing all the pages of the domain that created it. That is what shared means - it is allowed to serve multiple pages from a domain. Closing all domain pages invokes the shared worker's self-termination sequence.

  • Other worker types can also be killed by closing all domain pages.

Here is an example of terminating some unwelcome worker bots that steal your CPU:

// Create worker bots that consume CPU threads

var Blob = window.Blob;
var URL  = window.webkitURL || window.URL;


var numbots = 4;
var bots    = null; 
var bot     = "while(true){}"; // Nasty little botses!

bot = new Blob([bot], { type: 'text/javascript' });
bot = URL.createObjectURL(bot);

  
function terminator(){
    if (bots!=null){
        // Hasta la vista ...
        for (worker in bots)
            bots[worker].terminate();
        bots = null;
        document.getElementById("terminator").play();
        document.getElementById("button").src =  "https://dcerisano.github.io/assets/img/launch.jpg"
    }
    else{
        // Launch Intruders ...
        bots = [];
        for (var i=0; i<numbots; i++)
            bots[i] = new Worker(bot); 
        document.getElementById("alert").play(); 
        document.getElementById("button").src =  "https://dcerisano.github.io/assets/img/terminate.jpg"
    }
}
  
<img id="button" src="https://dcerisano.github.io/assets/img/launch.jpg" width="100%" onclick="terminator()">
<audio id="terminator" src="https://dcerisano.github.io/assets/audio/hastalavista.mp3">
<audio id="alert" src="https://dcerisano.github.io/assets/audio/alert.mp3">

  • Use your CPU monitor to confirm snippet is running.
  • Press button to terminate worker bots.
  • "Hide results" will close the snippet page/frame, also terminating worker bots.

Hopefully this answer will be useful to those wishing to build apps that hunt and kill unwelcome bots implemented as web workers (eg. bitmining bots that steal your electricity, bandwidth, and make you an accessory to Ponzi)

For example, this Chrome extension detects and selectively blocks web workers (all sorts of bots, including miners).

Upvotes: 4

mixer
mixer

Reputation: 59

I did this simple script and it seems the problem with FF and Chrome is still here:

    var myWorker = new Worker("w.js");

    myWorker.onmessage = function(e) {
        console.log('Message received from worker:'+e.data);
    }
    myWorker.postMessage(100);
    setTimeout(stopWW, 500) ;

    function stopWW(){
        console.log('TERMINATE');
        myWorker.terminate();
    }

while the webworker is:

    onmessage = function(e) {
      var n = e.data;
      console.log('Message received from main script:'+n);
      for (var i=0;i<n;i++){
        console.log('i='+i);
         postMessage(i);
      } 
    }

as soon as the main thread terminates the webworker so it does not receive postmessage any more BUT the webworker is still running under the scenes, this is an output:

"Message received from main script:100" w.js:3:2
"i=0" w.js:5:1
"Message received from worker:0" w.html:6:2
"i=1" w.js:5:1
...
"Message received from worker:21" w.html:6:2
"i=22" w.js:5:1
"TERMINATE" w.html:13:1
"i=23" w.js:5:1
"i=24" w.js:5:1
...
"i=99" w.js:5:1

Upvotes: 3

Sirko
Sirko

Reputation: 74046

You can kill any webworker using terminate().

Citing from MDN:

The Worker.terminate() method immediately terminates the Worker. This does not offer the worker an opportunity to finish its operations; it is simply stopped at once.

Upvotes: 17

Related Questions