diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml new file mode 100644 index 0000000..4b0c095 --- /dev/null +++ b/.github/workflows/nodejs.yml @@ -0,0 +1,16 @@ +name: CI + +on: + push: + branches: [ master ] + + pull_request: + branches: [ master ] + +jobs: + Job: + name: Node.js + uses: node-modules/github-actions/.github/workflows/node-test.yml@master + with: + os: 'ubuntu-latest, macos-latest, windows-latest' + version: '14, 16, 18, 20' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..1c6cbb1 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,13 @@ +name: Release + +on: + push: + branches: [ master ] + +jobs: + release: + name: Node.js + uses: node-modules/github-actions/.github/workflows/node-release.yml@master + secrets: + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + GIT_TOKEN: ${{ secrets.GIT_TOKEN }} diff --git a/.gitignore b/.gitignore index c0a6490..15719d9 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ results node_modules npm-debug.log coverage/ +package-lock.json diff --git a/History.md b/CHANGELOG.md similarity index 100% rename from History.md rename to CHANGELOG.md diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..b7fb850 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2014 - present node-modules and other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index 28aae4b..94d7ec4 100644 --- a/README.md +++ b/README.md @@ -2,19 +2,14 @@ cfork ======= [![NPM version][npm-image]][npm-url] -[![build status][travis-image]][travis-url] +[![Node.js CI](https://github.com/node-modules/cfork/actions/workflows/nodejs.yml/badge.svg)](https://github.com/node-modules/cfork/actions/workflows/nodejs.yml) [![Test coverage][codecov-image]][codecov-url] -[![Known Vulnerabilities][snyk-image]][snyk-url] [![npm download][download-image]][download-url] [npm-image]: https://img.shields.io/npm/v/cfork.svg?style=flat-square [npm-url]: https://npmjs.org/package/cfork -[travis-image]: https://img.shields.io/travis/node-modules/cfork.svg?style=flat-square -[travis-url]: https://travis-ci.org/node-modules/cfork [codecov-image]: https://codecov.io/gh/node-modules/cfork/branch/master/graph/badge.svg [codecov-url]: https://codecov.io/gh/node-modules/cfork -[snyk-image]: https://snyk.io/test/npm/cfork/badge.svg?style=flat-square -[snyk-url]: https://snyk.io/test/npm/cfork [download-image]: https://img.shields.io/npm/dm/cfork.svg?style=flat-square [download-url]: https://npmjs.org/package/cfork @@ -42,32 +37,29 @@ cfork({ exec: '/your/app/worker.js', // slaves: ['/your/app/slave.js'], // count: require('os').cpus().length, -}) -.on('fork', worker => { - console.warn('[%s] [worker:%d] new worker start', Date(), worker.process.pid); -}) -.on('disconnect', worker => { - console.warn('[%s] [master:%s] wroker:%s disconnect, exitedAfterDisconnect: %s, state: %s.', - Date(), process.pid, worker.process.pid, worker.exitedAfterDisconnect, worker.state); -}) -.on('exit', (worker, code, signal) => { - const exitCode = worker.process.exitCode; - const err = new Error(util.format('worker %s died (code: %s, signal: %s, exitedAfterDisconnect: %s, state: %s)', - worker.process.pid, exitCode, signal, worker.exitedAfterDisconnect, worker.state)); - err.name = 'WorkerDiedError'; - console.error('[%s] [master:%s] wroker exit: %s', Date(), process.pid, err.stack); -}) - -// if you do not listen to this event -// cfork will output this message to stderr -.on('unexpectedExit', (worker, code, signal) => { - // logger what you want -}); - -// emit when reach refork times limit -.on('reachReforkLimit', () => { - // do what you want -}); +}).on('fork', worker => { + console.warn('[%s] [worker:%d] new worker start', Date(), worker.process.pid); + }) + .on('disconnect', worker => { + console.warn('[%s] [master:%s] wroker:%s disconnect, exitedAfterDisconnect: %s, state: %s.', + Date(), process.pid, worker.process.pid, worker.exitedAfterDisconnect, worker.state); + }) + .on('exit', (worker, code, signal) => { + const exitCode = worker.process.exitCode; + const err = new Error(util.format('worker %s died (code: %s, signal: %s, exitedAfterDisconnect: %s, state: %s)', + worker.process.pid, exitCode, signal, worker.exitedAfterDisconnect, worker.state)); + err.name = 'WorkerDiedError'; + console.error('[%s] [master:%s] wroker exit: %s', Date(), process.pid, err.stack); + }) + // if you do not listen to this event + // cfork will output this message to stderr + .on('unexpectedExit', (worker, code, signal) => { + // logger what you want + }) + // emit when reach refork times limit + .on('reachReforkLimit', () => { + // do what you want + }); // if you do not listen to this event // cfork will listen it and output the error message to stderr @@ -92,30 +84,7 @@ process.on('uncaughtException', err => { ## License -``` -(The MIT License) - -Copyright (c) 2014 - 2017 node-modules and other contributors - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -'Software'), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -``` +[MIT](LICENSE) diff --git a/fixtures/slave.js b/fixtures/slave.js index 15c7352..c0d0840 100644 --- a/fixtures/slave.js +++ b/fixtures/slave.js @@ -14,6 +14,9 @@ var app = http.createServer(function (req, res) { if (req.url === '/env') { return res.end(process.env.CFORK_ENV_TEST); } + if (req.url === '/worker_index') { + return res.end(`worker index: ${process.env.CFORK_WORKER_INDEX}`); + } res.end(req.method + ' ' + req.url); }).listen(port); diff --git a/fixtures/worker.js b/fixtures/worker.js index 82a3124..a05bc67 100644 --- a/fixtures/worker.js +++ b/fixtures/worker.js @@ -24,6 +24,9 @@ var app = http.createServer(function (req, res) { if (req.url === '/env') { return res.end(process.env.CFORK_ENV_TEST); } + if (req.url === '/worker_index') { + return res.end(`worker index: ${process.env.CFORK_WORKER_INDEX}`); + } res.end(req.method + ' ' + req.url); }).listen(port); diff --git a/index.js b/index.js index c3a7d9f..78721d9 100644 --- a/index.js +++ b/index.js @@ -111,8 +111,9 @@ function fork(options) { disconnects[worker.process.pid] = utility.logDate(); if (allow()) { - newWorker = forkWorker(worker._clusterSettings); + newWorker = forkWorker(worker._clusterSettings, worker._clusterWorkerEnv); newWorker._clusterSettings = worker._clusterSettings; + newWorker._clusterWorkerEnv = worker._clusterWorkerEnv; log('[%s] [cfork:master:%s] new worker:%s fork (state: %s)', utility.logDate(), process.pid, newWorker.process.pid, newWorker.state); } else { @@ -141,8 +142,9 @@ function fork(options) { unexpectedCount++; if (allow()) { - newWorker = forkWorker(worker._clusterSettings); + newWorker = forkWorker(worker._clusterSettings, worker._clusterWorkerEnv); newWorker._clusterSettings = worker._clusterSettings; + newWorker._clusterWorkerEnv = worker._clusterWorkerEnv; log('[%s] [cfork:master:%s] new worker:%s fork (state: %s)', utility.logDate(), process.pid, newWorker.process.pid, newWorker.state); } else { @@ -167,18 +169,22 @@ function fork(options) { }); for (var i = 0; i < count; i++) { - newWorker = forkWorker(); + const env = { CFORK_WORKER_INDEX: String(i) }; + newWorker = forkWorker(null, env); newWorker._clusterSettings = cluster.settings; + newWorker._clusterWorkerEnv = env; } // fork slaves after workers are forked if (options.slaves) { var slaves = Array.isArray(options.slaves) ? options.slaves : [options.slaves]; slaves.map(normalizeSlaveConfig) - .forEach(function(settings) { + .forEach(function(settings, index) { if (settings) { - newWorker = forkWorker(settings); + const env = { CFORK_WORKER_INDEX: String(count + index) }; + newWorker = forkWorker(settings, env); newWorker._clusterSettings = settings; + newWorker._clusterWorkerEnv = env; } }); } @@ -264,12 +270,12 @@ function fork(options) { /** * fork worker with certain settings */ - function forkWorker(settings) { + function forkWorker(settings, workerEnv) { if (settings) { cluster.settings = settings; setupPrimary(); } - return cluster.fork(attachedEnv); + return cluster.fork(Object.assign({}, attachedEnv, workerEnv)); } /** diff --git a/test/cfork.test.js b/test/cfork.test.js index d48bac3..e49e2d0 100644 --- a/test/cfork.test.js +++ b/test/cfork.test.js @@ -1,12 +1,13 @@ 'use strict'; +var assert = require('assert'); var should = require('should'); var pedding = require('pedding'); var urllib = require('urllib'); var childprocess = require('childprocess'); var path = require('path'); -describe('cfork.test.js', function () { +describe('test/cfork.test.js', () => { var child; var messages = []; @@ -90,12 +91,35 @@ describe('cfork.test.js', function () { should.ifError(err); body.toString().should.equal('😂'); resp.statusCode.should.equal(200); - done(); + urllib.request('http://localhost:1985/worker_index', function (err, body, resp) { + should.ifError(err); + body.toString().should.equal('worker index: 4'); + resp.statusCode.should.equal(200); + done(); + }); }); }); }); }); + it('should get CFORK_WORKER_INDEX env value', function (done) { + urllib.request('http://localhost:1984/worker_index', function (err, body, resp) { + should.ifError(err); + const text = body.toString(); + // console.log('%o', text); + assert(text === 'worker index: 0' || text === 'worker index: 1' + || text === 'worker index: 2' || text === 'worker index: 3', text); + resp.statusCode.should.equal(200); + urllib.request('http://localhost:1985/worker_index', function (err, body, resp) { + should.ifError(err); + const text = body.toString(); + assert.equal(text, 'worker index: 4'); + resp.statusCode.should.equal(200); + done(); + }); + }); + }); + it('should slave exit', function (done) { urllib.request('http://localhost:1985/exit', function (err) { should.exist(err);