overleaf/services/spelling/app/coffee/ASpellWorkerPool.coffee

77 lines
2.2 KiB
CoffeeScript
Raw Normal View History

2015-03-04 11:43:59 -05:00
ASpellWorker = require "./ASpellWorker"
_ = require "underscore"
2015-03-10 09:33:05 -04:00
logger = require 'logger-sharelatex'
2015-03-12 05:54:57 -04:00
metrics = require('metrics-sharelatex')
2015-03-04 11:43:59 -05:00
class ASpellWorkerPool
2015-03-10 09:33:05 -04:00
MAX_REQUESTS: 100*1024
MAX_WORKERS: 32
MAX_IDLE_TIME: 1000
MAX_REQUEST_TIME: 60*1000
2015-03-10 09:33:05 -04:00
2015-03-04 11:43:59 -05:00
constructor: (@options) ->
@PROCESS_POOL = []
create: (language) ->
2015-03-10 09:33:05 -04:00
if @PROCESS_POOL.length >= @MAX_WORKERS
logger.log maxworkers: @MAX_WORKERS, "maximum number of workers already running"
return null
2015-03-04 11:43:59 -05:00
worker = new ASpellWorker(language, @options)
worker.pipe.on 'exit', () =>
if worker.killTimer?
clearTimeout worker.killTimer
worker.killTimer = null
if worker.idleTimer?
clearTimeout worker.idleTimer
worker.idleTimer = null
logger.log process: worker.pipe.pid, lang: language, "removing aspell worker from pool"
2015-03-11 10:53:06 -04:00
@cleanup()
2015-03-04 11:43:59 -05:00
@PROCESS_POOL.push(worker)
2015-03-12 05:54:57 -04:00
metrics.gauge 'aspellWorkerPool-size', @PROCESS_POOL.length
2015-03-04 11:43:59 -05:00
return worker
cleanup: () ->
active = @PROCESS_POOL.filter (worker) ->
worker.state != 'killed'
@PROCESS_POOL = active
2015-03-12 05:54:57 -04:00
metrics.gauge 'aspellWorkerPool-size', @PROCESS_POOL.length
2015-03-04 11:43:59 -05:00
check: (language, words, timeout, callback) ->
# look for an existing process in the pool
availableWorker = _.find @PROCESS_POOL, (cached) ->
cached.language == language && cached.isReady()
if not availableWorker?
worker = @create(language)
else
worker = availableWorker
2015-03-10 09:33:05 -04:00
if not worker?
# return error if too many workers
callback(new Error("no worker available"))
return
if worker.idleTimer?
clearTimeout worker.idleTimer
worker.idleTimer = null
worker.killTimer = setTimeout () ->
worker.kill("spell check timed out")
, timeout || @MAX_REQUEST_TIME
2015-03-10 09:33:05 -04:00
worker.check words, (err, output) =>
if worker.killTimer?
clearTimeout worker.killTimer
worker.killTimer = null
2015-03-04 11:43:59 -05:00
callback(err, output)
return if err? # process has shut down
2015-03-10 09:33:05 -04:00
if worker.count > @MAX_REQUESTS
worker.shutdown("reached limit of " + @MAX_REQUESTS + " requests")
else
# queue a shutdown if worker is idle
2015-03-10 09:33:05 -04:00
worker.idleTimer = setTimeout () ->
worker.shutdown("idle worker")
worker.idleTimer = null
, @MAX_IDLE_TIME
2015-03-04 11:43:59 -05:00
module.exports = ASpellWorkerPool