В итоге я создал список веб-серверов и поделился ими между задачами asyn c. внутри каждой задачи я могу вытащить веб-сервер из списка, использовать его, а затем вернуть его обратно в общий список веб-серверов.
Я отказался от использования get-port , и вместо этого я используя аналогичный метод, основанный на github gist
function getAvailablePort(startPort = 10000) {
let port = startPort
return () => {
const server = http.createServer()
return new Promise((resolve, reject) => server
.once('error', error => {
port += 1
error.code !== 'EADDRINUSE' ? reject(error) : server.listen(port)
})
.once('listening', () => server.close(() => {
port += 1
resolve(port)
}))
.listen(port)
)
}
}
Мой код теперь выглядит примерно так
(async () => {
let totalTasks = 0
let finishedSuccess = 0
let finishedWithError = 0
const concurrencyLimit = 18
try {
// create a pool of shared servers
const getNextPort = getAvailablePort()
const poolOfSharedServers = []
for(let i=0; i<concurrencyLimit; i++) {
let port = await getNextPort()
// create static files server and start listening
const server = http.createServer((request, response) => {
// You pass two more arguments for config and middleware
// More details here: https://github.com/zeit/serve-handler#options
return serveHandler(request, response, { public: 'dist' })
}).listen(port)
poolOfSharedServers.push(server)
}
// create async task
const asyncTask = createAsyncTask(poolOfSharedServers)
// build an async queue of tasks
const q = queue(async function(task) {
try {
const res = await asyncTask(task)
if (res.done) {
finishedSuccess += 1
await logger.saveLog(res.value)
} else {
finishedWithError += 1
}
} catch (err) {
finishedWithError += 1
}
}, concurrencyLimit)
// on all tasks finished
q.drain(function() {
console.log(`\nall ${totalTasks} tasks have been processed. ${finishedSuccess} finished successfully and ${finishedWithError} finished with errors\n`)
})
// on task error
q.error(function(err, task) {
finishedWithError += 1
console.error(`task ${JSON.stringify(task)} experienced an error`, err)
})
// create tasks
// tasks = ...
totalTasks = tasks.length
// push all tasks into the queue
q.push(tasks)
} catch (err) {
console.error(err)
}
})()
, где createAsyncTask
выглядит примерно так:
const createAsyncTask = (poolOfSharedServers) => async (task) => {
let result, server
try {
// get server out of shared pool of servers
server = poolOfSharedServers.pop()
// get current port
const port = server.address().port
// do some async work using task and server
await new Promise(resolve => setTimeout(resolve, 1000))
result = {
done: true,
value: 'some value'
}
} catch (err) {
result = {
done: false,
err
}
}
if (server) {
// add server back to the pool of shared servers
poolOfSharedServers.unshift(server)
}
return result
}