From 1a2860d3f408beec5173fe59b008f33c4fc6e707 Mon Sep 17 00:00:00 2001 From: Michael Gokhman Date: Mon, 8 Apr 2019 08:41:00 +0300 Subject: [PATCH] event-loop-spinner with async_hooks --- event-loop-spinner.js | 40 ++++++++++++++++++++++++++++++++++++++++ index.js | 15 +++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 event-loop-spinner.js diff --git a/event-loop-spinner.js b/event-loop-spinner.js new file mode 100644 index 0000000..391d769 --- /dev/null +++ b/event-loop-spinner.js @@ -0,0 +1,40 @@ +const async_hooks = require('async_hooks'); + +class EventLoopSpinner{ + constructor() { + this.hooksMap = {}; + this.blockedSince = Date.now(); + + const asyncHook = async_hooks.createHook({ + init: (asyncId, type, triggerAsyncId, resource) => { + this.hooksMap[asyncId] = {type}; + }, + before: (asyncId) => { + if (asyncId === 0) { + return; + } + if (!['TickObject', 'Microtask', 'PROMISE'].includes(this.hooksMap[asyncId].type)) { + this.blockedSince = Date.now(); + } + }, + destroy: (asyncId) => { + delete this.hooksMap[asyncId]; + } + }); + asyncHook.enable(); + } + + isStarving(thresholdMs = 100) { + return Date.now() - this.blockedSince > thresholdMs; + } + + async spin() { + return new Promise(setImmediate); + } +} + +const eventLoopSpinner = new EventLoopSpinner(); + +module.exports = { + eventLoopSpinner, +} diff --git a/index.js b/index.js index c4d1107..16bb531 100644 --- a/index.js +++ b/index.js @@ -1,6 +1,8 @@ const express = require('express'); const crypto = require('crypto'); +const {eventLoopSpinner} = require('./event-loop-spinner'); + const PID = process.pid; function log(msg) { @@ -74,6 +76,19 @@ app.get('/compute-with-set-immediate', async function computeWSetImmediate(req, res.send(hash.digest('hex') + '\n'); }); +app.get('/compute-with-spinner', async function computeWSetImmediate(req, res) { + log('computing async with event-loop-spinner!'); + + const hash = crypto.createHash('sha256'); + for (let i = 0; i < 10e6; i++) { + hash.update(randomString()); + if (eventLoopSpinner.isStarving()) { + await eventLoopSpinner.spin(); + } + } + res.send(hash.digest('hex') + '\n'); +}); + app.get('/compute-with-next-tick', async function computeWNextTick (req, res) { log('computing async with nextTick!');