Search code examples
node.jseventemitter

How to properly implement pause/resume in node.js for custom EventEmitter


I'm building a reporting service, where one process submits a query, retrieves a token, then hands off the token to another process, from which we query the reporting service and stream the results back.

Given this code, how should I implement the blocking call until paused is false?

var   util = require('util')
    , events = require('events')
    , pg = require('pg')

// QueryHandler is an EventEmitter
function QueryHandler(sql) {
  this.paused = true

  pg.connect(connectionString, function(err, client) {
    // error handling ignored for sake of illustration
    var query = client.query(sql)

    query.on('row', function(row) {
      if (this.paused) {
        // Somehow block until paused === false
      }

      this.emit(row)
    }.bind(this))
  }.bind(this))
}

util.inherits(QueryHandler, events.EventEmitter)

QueryHandler.prototype.resume = function() {
  this.paused = false
}

Here's an interaction diagram explaining what I'm trying to achieve:

  1. The web browser asks the frontend webserver for a report
  2. The frontend webserver asks the reporting service for a token relating to a specific query
  3. Simultaneously, the reporting service connects to PostgreSQL and sends the query
  4. The frontend webserver returns the reporting service's URL and token back to the web browser
  5. The web browser does an Ajax (long polling) request to the reporting service with the returned token
  6. The reporting service streams rows as they come in back to the web browser

Because everything is asynchronous, step 3 might start returning data before the web browser connects, which would mean data loss. I could buffer the data in memory until the client comes back, but I'd rather block the emission of data rows, since that would prevent RAM use. Or maybe I'm just kidding myself and RAM will still be used in the underlying library? Anyway, pointers appreciated!


Solution

  • If you're going to block in the event-loop I think you have to wait for the web-workers api (threads, sort of) to be implemented.

    I think saving the rows coming from pg is a better idea.