meshblu-core-job-manager
Version:
Meshblu Core Job Manager
140 lines (113 loc) • 4.76 kB
text/coffeescript
_ = require 'lodash'
async = require 'async'
JobManagerBase = require './base'
debug = require('debug')('meshblu-core-job-manager:responder')
debugSaturation = require('debug')('meshblu-core-job-manager:responder:saturation')
SimpleBenchmark = require 'simple-benchmark'
ResponderDequeuer = require './responder-dequeuer'
class JobManagerResponder extends JobManagerBase
constructor: (options={}) ->
{
concurrency
} = options
throw new Error 'JobManagerResponder constructor is missing "requestQueueName"' unless ?
throw new Error 'JobManagerResponder constructor is missing "workerFunc"' unless ?
concurrency ?= 1
= async.queue , concurrency
.empty = => 'empty'
super
= []
_.times Math.ceil(concurrency/3), (x) =>
.push new ResponderDequeuer { , , , , , x, }
onPush: =>
= false
createResponse: ({responseId, response}, callback) =>
{ metadata, data, rawData } = response
metadata.responseId ?= responseId
data ?= null
rawData ?= JSON.stringify data
.hmget metadata.responseId, ['request:metadata', 'response:queueName'], (error, result) =>
delete error.code if error?
return callback error if error?
[ requestMetadata, responseQueueName ] = result ? []
return callback() if _.isEmpty(requestMetadata) and _.isEmpty(responseQueueName)
return callback new Error 'missing responseQueueName' unless responseQueueName?
try
requestMetadata = JSON.parse requestMetadata
catch
requestMetadata ?= {}
if requestMetadata.ignoreResponse
.del metadata.responseId, (error) =>
delete error.code if error?
return callback error if error?
return callback null, {metadata, rawData}
return
metadata.jobLogs = requestMetadata.jobLogs if requestMetadata.jobLogs?
metadata.metrics = requestMetadata.metrics if requestMetadata.metrics?
metadata, 'enqueueResponseAt', (error) =>
return callback error if error?
async.series [
async.apply .publish, responseQueueName, JSON.stringify({ metadata, rawData })
async.apply .expire, metadata.responseId,
], (error) =>
delete error.code if error?
callback null, { metadata, rawData }
return # avoid returning redis
_work: (key, callback) =>
benchmark = new SimpleBenchmark label: '_work'
key, (error, job) =>
return callback error if error?
process.nextTick =>
job, (error, response) =>
if error?
console.error error.stack
callback()
return callback() if job.metadata.ignoreResponse
responseId = _.get job, 'metadata.responseId'
{responseId, response}, (error) =>
console.error error.stack if error?
debug benchmark.toString()
callback()
getRequest: (key, callback) =>
.hgetall key, (error, result) =>
delete error.code if error?
return callback error if error?
return callback new Error 'Missing result' if _.isEmpty result
return callback new Error 'Missing metadata' if _.isEmpty result['request:metadata']
metadata = JSON.parse result['request:metadata']
metadata, 'dequeueRequestAt', (error) =>
return callback error if error?
request =
createdAt: result['request:createdAt']
metadata: metadata
rawData: result['request:data']
.hset key, 'request:metadata', JSON.stringify(metadata), (error) =>
return callback error if error?
callback null, request
start: (callback=_.noop) =>
.acquire().then () =>
.once 'error', (error) =>
'error', error
callback
.catch callback
return # promises
_startProcessing: (callback) =>
= true
.drain = =>
debug 'drained'
= true
tasks = []
_.each , (dequeuer) =>
tasks.push dequeuer.start
async.parallel tasks, callback
_waitForStopped: (callback) =>
_.delay callback, 100
stop: (callback=_.noop) =>
tasks = []
_.each , (dequeuer) =>
tasks.push dequeuer.stop
async.parallel tasks, =>
async.doUntil , (=> ), callback
module.exports = JobManagerResponder