UNPKG

5.72 kBJavaScriptView Raw
1/**
2 * Copyright 2013 the PM2 project authors. All rights reserved.
3 * Use of this source code is governed by a license that
4 * can be found in the LICENSE file.
5 */
6var vizion = require('vizion');
7var cst = require('../constants.js');
8var eachLimit = require('async/eachLimit');
9var debug = require('debug')('pm2:worker');
10var domain = require('domain');
11var cronJob = require('cron').CronJob
12
13module.exports = function(God) {
14 var timer = null;
15
16 God.CronJobs = new Map();
17 God.Worker = {};
18 God.Worker.is_running = false;
19
20 var _getProcessById = function(pm_id) {
21 var proc = God.clusters_db[pm_id];
22 return proc ? proc : null;
23 };
24
25 var registerCron = function(proc_key) {
26 var proc = _getProcessById(proc_key.pm2_env.pm_id);
27
28 if (!proc ||
29 !proc.pm2_env ||
30 proc.pm2_env.pm_id === undefined ||
31 !proc.pm2_env.cron_restart ||
32 God.CronJobs.has(proc.pm2_env.pm_id))
33 return;
34
35 console.log('[PM2][WORKER] Registering a cron job on:', proc.pm2_env.pm_id);
36
37 var job = new cronJob({
38 cronTime: proc.pm2_env.cron_restart,
39 onTick: function() {
40 God.softReloadProcessId({id: proc.pm2_env.pm_id}, function(err, data) {
41 if (err)
42 console.error(err.stack || err);
43 return;
44 });
45 },
46 start: false
47 });
48
49 job.start();
50 God.CronJobs.set(proc.pm2_env.pm_id, job);
51 };
52
53
54 var maxMemoryRestart = function(proc_key, cb) {
55 var proc = _getProcessById(proc_key.pm2_env.pm_id);
56
57 if (!(proc &&
58 proc.pm2_env &&
59 proc_key.monit))
60 return cb();
61
62 if (proc_key.monit.memory !== undefined &&
63 proc.pm2_env.max_memory_restart !== undefined &&
64 proc.pm2_env.max_memory_restart < proc_key.monit.memory &&
65 proc.pm2_env.axm_options &&
66 proc.pm2_env.axm_options.pid === undefined) {
67 console.log('[PM2][WORKER] Process %s restarted because it exceeds --max-memory-restart value (current_memory=%s max_memory_limit=%s [octets])', proc.pm2_env.pm_id, proc_key.monit.memory, proc.pm2_env.max_memory_restart);
68 God.softReloadProcessId({
69 id : proc.pm2_env.pm_id
70 }, function(err, data) {
71 if (err)
72 console.error(err.stack || err);
73 return cb();
74 });
75 }
76 else {
77 return cb();
78 }
79 };
80
81 // Deprecated
82 var versioningRefresh = function(proc_key, cb) {
83 var proc = _getProcessById(proc_key.pm2_env.pm_id);
84 if (!(proc &&
85 proc.pm2_env &&
86 (proc.pm2_env.vizion !== false && proc.pm2_env.vizion != "false") &&
87 proc.pm2_env.versioning &&
88 proc.pm2_env.versioning.repo_path)) {
89 return cb();
90 }
91
92 if (proc.pm2_env.vizion_running === true)
93 {
94 debug('Vizion is already running for proc id: %d, skipping this round', proc.pm2_env.pm_id);
95 return cb();
96 }
97
98 proc.pm2_env.vizion_running = true;
99 var repo_path = proc.pm2_env.versioning.repo_path;
100
101 vizion.analyze({
102 folder: proc.pm2_env.versioning.repo_path
103 },
104 function(err, meta) {
105 if (err != null)
106 return cb();
107
108 proc = _getProcessById(proc_key.pm2_env.pm_id);
109
110 if (!(proc &&
111 proc.pm2_env &&
112 proc.pm2_env.versioning &&
113 proc.pm2_env.versioning.repo_path)) {
114 console.error('Proc not defined anymore or versioning unknown');
115 return cb();
116 }
117
118 proc.pm2_env.vizion_running = false;
119 meta.repo_path = repo_path;
120 proc.pm2_env.versioning = meta;
121 debug('[PM2][WORKER] %s parsed for versioning', proc.pm2_env.name);
122 return cb();
123 });
124 };
125
126 var tasks = function() {
127 if (God.Worker.is_running === true) {
128 debug('[PM2][WORKER] Worker is already running, skipping this round');
129 return false;
130 }
131 God.Worker.is_running = true;
132
133 God.getMonitorData(null, function(err, data) {
134 if (err || !data || typeof(data) !== 'object') {
135 God.Worker.is_running = false;
136 return console.error(err);
137 }
138
139 eachLimit(data, 1, function(proc, next) {
140 if (!proc || !proc.pm2_env || proc.pm2_env.pm_id === undefined)
141 return next();
142
143 debug('[PM2][WORKER] Processing proc id:', proc.pm2_env.pm_id);
144
145 // Reset restart delay if application has an uptime of more > 30secs
146 if (proc.pm2_env.exp_backoff_restart_delay !== undefined &&
147 proc.pm2_env.prev_restart_delay && proc.pm2_env.prev_restart_delay > 0) {
148 var app_uptime = Date.now() - proc.pm2_env.pm_uptime
149 if (app_uptime > cst.EXP_BACKOFF_RESET_TIMER) {
150 var ref_proc = _getProcessById(proc.pm2_env.pm_id);
151 ref_proc.pm2_env.prev_restart_delay = 0
152 console.log(`[PM2][WORKER] Reset the restart delay, as app ${proc.name} is up for more than ${cst.EXP_BACKOFF_RESET_TIMER}`)
153 }
154 }
155
156 registerCron(proc);
157 // Check if application has reached memory threshold
158 maxMemoryRestart(proc, function() {
159 return next();
160 });
161 }, function(err) {
162 God.Worker.is_running = false;
163 debug('[PM2][WORKER] My job here is done, next job in %d seconds', parseInt(cst.WORKER_INTERVAL / 1000));
164 });
165 });
166 };
167
168 var wrappedTasks = function() {
169 var d = domain.create();
170
171 d.once('error', function(err) {
172 console.error('[PM2][WORKER] Error caught by domain:\n' + (err.stack || err));
173 God.Worker.is_running = false;
174 });
175
176 d.run(function() {
177 tasks();
178 });
179 };
180
181
182 God.Worker.start = function() {
183 timer = setInterval(wrappedTasks, cst.WORKER_INTERVAL);
184 };
185
186 God.Worker.stop = function() {
187 if (timer !== null)
188 clearInterval(timer);
189 };
190};