Multicast Service Discovery

Auf der Suche nach einer einfachen Möglichkeit Service Discovery für eigene Node.js Services zu machen, habe ich nach einigen nicht sehr erfolgsversprechenden Versuchen mit mdns(bonjour) begonnen einen Multicast Server zu schreiben. Aus diesem Proof-of-Concept ist inzwischen ein Middleware-fähiger Multicast Server entstanden.

Quellen, Beispiele und Dokumentation sind auf github zu finden
https://github.com/skenqbx/node-caster

Das Modul in der aktuellsten Version lässt sich über ’npm install caster‘ installieren.

 


Sichere Verwendung von Callbacks in Node.js

Beim asynchronen Programmieren kommt es oft darauf an, sicherzustellen das Callbacks auch tatsächlich zurückkommen bzw. nur ein einziges mal zurückkommen.

Um dieses Problem zu abstrahieren nutze ich selbst folgende Funktion:

function wrap(callback, timeout) {
  if (callback._timeoutId && callback._callback) {
    clearTimeout(callback._timeoutId);
    callback = callback._callback;
    return callback;
  }

  var returned = false;

  function onTimeout() {
    returned = true;
    var err = new Error('Timeout expired');
    err.code = 'EWRAPTO';
    callback(err);
  }

  var wrapper = function() {
    clearTimeout(wrapper._timeoutId);
    if (!returned) {
      var args = Array.prototype.slice.call(arguments);
      callback.apply({}, args);
    } else {
      throw new Error('Duplicate callback');
    }
  };

  wrapper._callback = callback;
  wrapper._timeoutId = setTimeout(onTimeout, timeout || 1000);

  return wrapper;
}

Die Verwendung ist wie folgt:

dns.lookup('www.joocom.de', wrap(function(err, address, family) {
  // Will be executed exactly one-time.
  // Either on return from dns.lookup(),
  //   or when the timeout of 1000ms expired.
}, 1000));

Viel Spaß!




node.js: CPU intensive Berechnungen ohne die Event Loop zu blockieren

Wenn ein node.js Programm viel auf der CPU rechnen muss ist für die Dauer dieser Berechnungen die Event Loop blockiert. Folgendes Programm, welches sich nach 10s beenden sollte, funktioniert deswegen nicht wie erwartet:

setTimeout(function() { process.exit(0); }, 10000);
for(;;) {
doSomething();
}

Die Timeout Funktion wird nie ausgeführt, weil die for-Schleife die Kontrolle niemals an die Event Loop zurückgibt.

Um das Problem zu umgehen muss die for-Schleife die Kontrolle bei jeder Iteration kurzzeitig an die Event Loop abgeben. Hierzu wird der Aufruf in eine Funktion geschachtelt, welche die eigentliche Funktion ausführt und sich nach einem Timeout von 1ms selbst aufruft:

setTimeout(function() { process.exit(0); }, 10000);
function wrapper(fn) {
fn();
setTimeout(wrapper.bind(this, fn), 1);
}
wrapper(doSomething);

Hierdurch ist gewährleistet das die Event Loop nicht blockiert und sich das Programm tatsächlich nach 10s beendet.

Noch ein Hinweis zur vermeintlichen Rekursion; es findet keine Rekursion statt, da wrapper() nach dem ersten Aufruf immer von der Event Loop aus aufgerufen wird.