UNPKG

4.8 kBJavaScriptView Raw
1var path = require ('path');
2var cluster = require ('cluster');
3var os = require ('os');
4
5var numCPUs = os.cpus().length;
6
7var dataflows = require ('dataflo.ws');
8var minimist = require ('commop/lib/minimist');
9
10module.exports = {
11 launchContext: function () {
12 var argv = minimist(process.argv.slice(3));
13 return {
14 configKey: argv._[0],
15 method: argv._[1],
16 args: argv
17 };
18 },
19 launch: function (conf) {
20 var ctx = this.launchContext();
21 var daemonName = ctx.configKey;
22
23 if ('fork' in ctx.args && !ctx.args.fork) {
24 runDaemon (conf, daemonName);
25
26 return;
27 }
28
29 // instead of forking, cluster launch new script instance
30
31 if (cluster.isMaster) {
32 // Fork workers. TODO: make worker number configurable
33 for (var i = 0; i < numCPUs; i++) {
34 cluster.fork();
35 }
36
37 cluster.on('exit', function(worker, code, signal) {
38 // TODO: relaunch worker?
39 console.log('worker ' + worker.process.pid + ' died, code: ' + code + ', signal:' + signal);
40 if (code != 0) {
41 console.log("worker crashed! spawning a replacement.");
42 cluster.fork();
43 }
44 });
45
46 // process.on ('SIGINT', killWorkers);
47 // process.on ('SIGTERM', killWorkers);
48 // process.on ('SIGBREAK', killWorkers);
49 // process.on ('SIGINT', gracefullyRestartWorkers);
50
51 process.on ('SIGHUP', gracefullyRestartWorkers);
52
53 } else {
54 // Workers can share any TCP connection
55
56 runDaemon (conf, daemonName);
57 }
58
59 // watch config directories and node_modules directories when debug
60 if (!project.config.debug) {
61 return;
62 }
63
64 return;
65
66 setupWatcher ();
67 }
68}
69
70function killWorkers () {
71 Object.keys(cluster.workers).forEach (function (workerNum) {
72 cluster.workers[workerNum].kill ();
73 });
74}
75
76function gracefullyRestartWorkers () {
77 // only reload one worker at a time
78 // otherwise, we'll have a time when no request handlers are running
79 var i = 0;
80 var workers = Object.keys(cluster.workers);
81 var f = function() {
82 if (i == workers.length) return;
83
84 console.log("Killing " + workers[i]);
85
86 cluster.workers[workers[i]].disconnect();
87 cluster.workers[workers[i]].on("disconnect", function() {
88 console.log("worker shutdown complete");
89 });
90
91 // TODO: set timeout and kill worker
92
93 var newWorker = cluster.fork();
94 newWorker.on("listening", function() {
95 console.log("replacement worker online.");
96 i++;
97 f();
98 });
99 }
100 f();
101}
102
103
104
105function runDaemon (conf, daemonName) {
106 var configDaemonNames = Object.keys(conf.daemon);
107 if (daemonName == undefined && configDaemonNames.length == 1)
108 daemonName = configDaemonNames[0];
109 if (!conf.daemon || !conf.daemon[daemonName]) {
110 // TODO: add description for daemon config generation
111 console.error(
112 'No daemon named "%s" found in configuration', daemonName
113 );
114 var logDaemonNames = configDaemonNames.join ('", "');
115 console.error ('You can select one from those daemon configurations: "%s"', logDaemonNames);
116 process.exit();
117 }
118
119 var daemonConf = conf.daemon[daemonName];
120 var initiatorTypes = daemonConf.initiator;
121
122 var initiators = {};
123
124 initiatorTypes.forEach(function (initiatorType) {
125 var initiatorConf = conf.initiator[initiatorType];
126 // setters and getters is a flimsy shim for languages
127 // without lvalue
128 var initiatorClass = dataflows.initiator (initiatorType);
129
130 if ('function' == typeof initiatorClass) {
131 initiators[initiatorType] = new initiatorClass (initiatorConf, initiators);
132 } else {
133 console.error('Cannot load initiator "%s"', initiatorType);
134 }
135 });
136}
137
138function setupWatcher () {
139
140 if (os.platform() === "darwin") {
141 var fsevents = require('fsevents');
142 var watcher = fsevents(__dirname);
143 watcher.on('fsevent', function(path, flags, id) { }); // RAW Event as emitted by OS-X
144 watcher.on('change', function(path, info) {}); // Common Event for all changes
145 watcher.start() // To start observation
146 watcher.stop() // To end observation
147 } else {
148
149 }
150 var chokidar = require ('chokidar');
151
152 var watcher = chokidar.watch([
153 path.join (project.root.path, '.dataflows'),
154 path.join (project.root.path, 'node_modules')
155 ], {
156 // ignored: /[\/\\]\./,
157 persistent: true
158 });
159
160 // Add event listeners
161 watcher
162 .on('add', function(path) { log('File', path, 'has been added'); })
163 .on('change', function(path) { log('File', path, 'has been changed'); })
164 .on('unlink', function(path) { log('File', path, 'has been removed'); })
165 // More events.
166 .on('addDir', function(path) { log('Directory', path, 'has been added'); })
167 .on('unlinkDir', function(path) { log('Directory', path, 'has been removed'); })
168 .on('error', function(error) { log('Error happened', error); })
169 .on('ready', function() { log('Initial scan complete. Ready for changes.'); })
170 .on('raw', function(event, path, details) { log('Raw event info:', event, path, details); })
171
172}