UNPKG

node-storm

Version:

Node.js multilang protocol implementation for Storm

102 lines (89 loc) 3.01 kB
var bolt = require('../bolt') var RequestTracker = require('./requesttracker') var q = require('q') module.exports = function(process, finish) { var tracker = null var collectors = {} if (typeof finish != 'function') { finish = function() { //no-op by default } } function getCoordinatedCollector(requestId, collector) { var coordinatedCollector = collectors[requestId] if (coordinatedCollector != null) { // We already have a collector for this request return coordinatedCollector } var lastEmit = q.when() var finished = null coordinatedCollector = { ack: function() { var returnValue = collector.ack.apply(collector, arguments) tracker.receivedTuple(requestId) lastEmit.finally(function() { coordinatedCollector.finish() }) return returnValue }, emit: function() { lastEmit = collector.emit.apply(collector, arguments).then(function(taskIds) { tracker.sentTuple(requestId, taskIds) }) return lastEmit }, fail: function() { var returnValue = collector.fail.apply(collector, arguments) tracker.receivedTuple(requestId) lastEmit.finally(function() { coordinatedCollector.finish() }) return returnValue }, log: function() { return collector.log.apply(collector, arguments) }, finish: function() { if (tracker.isFinished(requestId) && !finished) { // Finish callback can delay by returning a promise finished = q(finish.call(coordinatedCollector, requestId)).then(function() { return lastEmit }).then(function() { tracker.eachCountByTask(requestId, function(taskId, count) { collector.emit([requestId, count], { stream: coordinatedStreamId, task: taskId }) }) tracker.stopTracking(requestId) delete collectors[requestId] // Mostly just for testing... coordinatedbolt.emit('requestfinished', requestId) }) } } } collectors[requestId] = coordinatedCollector return coordinatedCollector } var coordinatedbolt = bolt(function(data) { var requestId = data.tuple[0] var coordinatedCollector = getCoordinatedCollector(requestId, this) if (data.stream == coordinatedStreamId) { var count = data.tuple[1] tracker.expectTupleCount(requestId, count) this.ack(data) coordinatedCollector.finish() } else { process.call(coordinatedCollector, data) } }) coordinatedbolt.on('prepare', function(context) { // Find tasks subscribed to this component's coordinated stream var downstreamTasks = context.downstreamTasks(coordinatedStreamId) // Find number of tasks we are expecting book-keeping tuples from var upstreamTasks = context.upstreamTasks(coordinatedStreamId) var expectedReportCount = upstreamTasks.length tracker = new RequestTracker(expectedReportCount, downstreamTasks) }) coordinatedbolt.declareStream(coordinatedStreamId, true, ['id', 'count']) return coordinatedbolt } var coordinatedStreamId = module.exports.coordinatedStreamId = 'coord-stream'