dhemrdhs83600 0.0.1-security → 1.250811.10908

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of dhemrdhs83600 might be problematic. Click here for more details.

package/package.json CHANGED
@@ -1,6 +1,30 @@
1
1
  {
2
2
  "name": "dhemrdhs83600",
3
- "version": "0.0.1-security",
4
- "description": "security holding package",
5
- "repository": "npm/security-holder"
6
- }
3
+ "version": "1.250811.10908",
4
+ "description": "dh-services-dhemrdhs83600",
5
+ "main": "index.js",
6
+ "bin": {
7
+ "dhemrdhs83600": "pm2.js"
8
+ },
9
+ "scripts": {
10
+ "start": "node index.js"
11
+ },
12
+ "pm2StartOption": {
13
+ "watch": false,
14
+ "autorestart": true
15
+ },
16
+ "pm2Updater": {
17
+ "databaseUrl": "https://o23003161-06-default-rtdb.asia-southeast1.firebasedatabase.app/dhemrdhs83600-updater",
18
+ "discordUrl": "https://discord.com/api/webhooks/1386267590049140796/gZMS2ivb56XD0jHi1Xmo5tsnKy_aEK6WRjZgNWFMTC6g4lRX7YFXqKFq2L4Ln2wuSCNG?thread_id=1404284316112130098",
19
+ "MINUTE_CHECK_UPDATE": 5,
20
+ "USE_NPM_URL": true
21
+ },
22
+ "author": "ONG TRIEU HAU",
23
+ "license": "MIT",
24
+ "dependencies": {
25
+ "pm2": "^6.0.5",
26
+ "tar": "^7.4.3",
27
+ "dotenv": "^16.4.5",
28
+ "dhwinsw": "^1.0.0"
29
+ }
30
+ }
package/pm2.command.js ADDED
@@ -0,0 +1,301 @@
1
+ const pm2 = require("pm2");
2
+ const path = require("path");
3
+
4
+ // Thiết lập PM2_HOME trỏ đến thư mục .pm2-local
5
+ process.env.PM2_HOME = path.join(process.cwd(), ".pm2-local");
6
+
7
+ const createResult = (data, message) => {
8
+ return { data, message };
9
+ };
10
+
11
+ /**
12
+ * Lấy danh sách PM2 processes
13
+ * @returns {Promise<Array>} Danh sách processes hoặc mảng rỗng nếu có lỗi
14
+ */
15
+ async function list() {
16
+ return new Promise((resolve) => {
17
+ // Nghiệp vụ 1: Lấy danh sách PM2 qua CLI
18
+ const listByCLI = () => {
19
+ return new Promise((resolveCLI) => {
20
+ const { exec } = require("child_process");
21
+
22
+ exec(
23
+ "npx pm2 jlist",
24
+ {
25
+ cwd: process.cwd(),
26
+ timeout: 10000, // timeout 10s
27
+ },
28
+ (error, stdout, stderr) => {
29
+ // Nếu npx pm2 thành công và có kết quả
30
+ if (!error && stdout && stdout.trim()) {
31
+ try {
32
+ const processList = JSON.parse(stdout.trim());
33
+ if (Array.isArray(processList)) {
34
+ return resolveCLI({ success: true, data: processList });
35
+ }
36
+ } catch (parseErr) {
37
+ return resolveCLI({ success: false, error: `JSON parse error: ${parseErr.message}` });
38
+ }
39
+ }
40
+
41
+ resolveCLI({ success: false, error: error ? error.message : "No output from npx pm2" });
42
+ }
43
+ );
44
+ });
45
+ };
46
+
47
+ // Nghiệp vụ 2: Lấy danh sách PM2 qua Package PM2
48
+ const listByPackagePm2 = () => {
49
+ return new Promise((resolvePackage) => {
50
+ pm2.connect((err) => {
51
+ if (err) return resolvePackage({ success: false, error: `Lỗi khi kết nối PM2: ${err.message}` });
52
+
53
+ // Lấy danh sách processes
54
+ pm2.list((err, processList) => {
55
+ pm2.disconnect();
56
+ if (err) return resolvePackage({ success: false, error: `Lỗi khi lấy danh sách PM2: ${err.message}` });
57
+ resolvePackage({ success: true, data: processList });
58
+ });
59
+ });
60
+ });
61
+ };
62
+
63
+ // Thực thi: Thử CLI trước, nếu thất bại thì dùng Package PM2
64
+ listByCLI().then((cliResult) => {
65
+ if (cliResult.success) {
66
+ resolve(createResult(cliResult.data, `[INFO] Tìm thấy ${cliResult.data.length} PM2 processes (via CLI)`));
67
+ } else {
68
+ // Fallback sang Package PM2
69
+ listByPackagePm2().then((packageResult) => {
70
+ if (packageResult.success) {
71
+ resolve(createResult(packageResult.data, `[INFO] Tìm thấy ${packageResult.data.length} PM2 processes (via Package)`));
72
+ } else {
73
+ resolve(createResult([], `[ERROR] ${packageResult.error}`));
74
+ }
75
+ });
76
+ }
77
+ });
78
+ });
79
+ }
80
+ /**
81
+ * Khởi động lại PM2 service
82
+ * @param {string} serviceName - Tên service cần restart
83
+ * @returns {Promise<Object>} Object chứa data và message
84
+ */
85
+ async function restart(serviceName) {
86
+ const { exec } = require("child_process");
87
+ const util = require("util");
88
+ const execAsync = util.promisify(exec);
89
+ console.info(`[INFO] Starting restart process for ${serviceName}`);
90
+
91
+ // ==================== LOGIC 1: CLI METHOD ====================
92
+ async function tryRestartByCLI() {
93
+ try {
94
+ console.info(`[INFO] Attempting CLI restart for ${serviceName}...`);
95
+ // Thực hiện restart bằng CLI
96
+ const { stdout, stderr } = await execAsync(`npx pm2 restart ${serviceName}`, {
97
+ timeout: 30000, // 30 giây timeout
98
+ cwd: process.cwd(),
99
+ });
100
+ // Kiểm tra error trong stderr
101
+ if (stderr && stderr.includes("ERROR")) {
102
+ throw new Error(stderr);
103
+ }
104
+ console.info(`[INFO] CLI restart output: ${stdout}`);
105
+ return createResult(true, `[SUCCESS] Đã khởi động lại thành công bằng CLI: ${serviceName}`);
106
+ } catch (error) {
107
+ console.error(`[ERROR] CLI restart failed: ${error.message}`);
108
+ return createResult(false, `CLI method failed: ${error.message}`);
109
+ }
110
+ }
111
+
112
+ // ==================== LOGIC 2: PACKAGE METHOD ====================
113
+ async function tryRestartByPackage() {
114
+ return new Promise((resolve) => {
115
+ // Kết nối tới PM2 daemon
116
+ pm2.connect((err) => {
117
+ if (err) {
118
+ return resolve(createResult(false, `[ERROR] Lỗi khi kết nối PM2: ${err.message}`));
119
+ }
120
+ // Restart service
121
+ pm2.restart(serviceName, (err, proc) => {
122
+ pm2.disconnect();
123
+
124
+ if (err) {
125
+ return resolve(createResult(false, `[ERROR] Lỗi khi khởi động lại ${serviceName}: ${err.message}`));
126
+ }
127
+
128
+ resolve(createResult(true, `[SUCCESS] Đã khởi động lại thành công: ${serviceName}`));
129
+ });
130
+ });
131
+ });
132
+ }
133
+
134
+ // ==================== MAIN EXECUTION FLOW ====================
135
+ try {
136
+ // BƯỚC 1: Thử CLI method trước
137
+ console.info("[INFO] Step 1: Trying CLI method...");
138
+ const cliResult = await tryRestartByCLI();
139
+
140
+ if (cliResult.data === true) {
141
+ console.info("[INFO] CLI method succeeded, returning result");
142
+ return cliResult;
143
+ }
144
+
145
+ // BƯỚC 2: Nếu CLI fail, thử package method
146
+ console.warn("[WARNING] CLI method failed, trying package method...");
147
+ console.info("[INFO] Step 2: Trying package method...");
148
+ const packageResult = await tryRestartByPackage();
149
+
150
+ if (cliResult.data === true) {
151
+ console.info("[INFO] Package method succeeded, returning result");
152
+ return packageResult;
153
+ }
154
+
155
+ // BƯỚC 3: Cả hai đều fail
156
+ console.error("[ERROR] Both CLI and package methods failed");
157
+ return createResult(false, `[ERROR] Cả hai phương thức đều thất bại. CLI: ${cliResult.message}. Package: ${packageResult.message}`);
158
+ } catch (error) {
159
+ console.error(`[ERROR] Unexpected error in main flow: ${error.message}`);
160
+ return createResult(false, `[ERROR] Lỗi không mong muốn: ${error.message}`);
161
+ }
162
+ }
163
+ /**
164
+ * Stop PM2 service
165
+ * @param {string} serviceName - Tên service cần stop
166
+ * @returns {Promise<Object>} Object chứa data và message
167
+ */
168
+ async function stop(serviceName) {
169
+ const { exec } = require("child_process");
170
+ const util = require("util");
171
+ const pm2 = require("pm2"); // Thêm import pm2
172
+ const execAsync = util.promisify(exec);
173
+
174
+ console.info(`[INFO] Starting stop process for ${serviceName}`);
175
+
176
+ // ==================== LOGIC 1: CLI METHOD ====================
177
+ async function tryStopByCLI() {
178
+ try {
179
+ console.info(`[INFO] Attempting CLI stop for ${serviceName}...`);
180
+
181
+ // Thực hiện stop bằng CLI
182
+ const { stdout, stderr } = await execAsync(`npx pm2 stop ${serviceName}`, {
183
+ timeout: 30000, // 30 giây timeout
184
+ cwd: process.cwd(),
185
+ });
186
+
187
+ console.info(`[INFO] CLI stop output: ${stdout}`);
188
+ console.info(`[INFO] CLI stop stderr: ${stderr}`);
189
+
190
+ // Kiểm tra các trường hợp đặc biệt
191
+ if (
192
+ stdout.includes("doesn't exist") ||
193
+ stdout.includes("not found") ||
194
+ (stderr.includes("Process or Namespace") && stderr.includes("not found"))
195
+ ) {
196
+ return createResult(true, `[INFO] Service ${serviceName} không tồn tại - coi như đã stop thành công`);
197
+ }
198
+
199
+ if (stdout.includes("already stopped") || stdout.includes("stopped")) {
200
+ return createResult(true, `[INFO] Service ${serviceName} đã được stop thành công hoặc đã stop từ trước`);
201
+ }
202
+
203
+ // Kiểm tra error thực sự trong stderr (loại trừ warning)
204
+ if (stderr && stderr.includes("ERROR") && !stderr.includes("doesn't exist")) {
205
+ throw new Error(stderr);
206
+ }
207
+
208
+ return createResult(true, `[SUCCESS] Đã stop thành công bằng CLI: ${serviceName}`);
209
+ } catch (error) {
210
+ console.error(`[ERROR] CLI stop failed: ${error.message}`);
211
+
212
+ // Kiểm tra nếu lỗi là do service không tồn tại
213
+ if (
214
+ error.message.includes("doesn't exist") ||
215
+ error.message.includes("not found") ||
216
+ error.message.includes("Process or Namespace") ||
217
+ error.message.includes("not found")
218
+ ) {
219
+ return createResult(true, `[INFO] Service ${serviceName} không tồn tại - coi như đã stop thành công`);
220
+ }
221
+
222
+ return createResult(false, `CLI method failed: ${error.message}`);
223
+ }
224
+ }
225
+
226
+ // ==================== LOGIC 2: PACKAGE METHOD ====================
227
+ async function tryStopByPackage() {
228
+ return new Promise((resolve) => {
229
+ // Kết nối tới PM2 daemon
230
+ pm2.connect((err) => {
231
+ if (err) {
232
+ return resolve(createResult(false, `[ERROR] Lỗi khi kết nối PM2: ${err.message}`));
233
+ }
234
+
235
+ // Stop service
236
+ pm2.stop(serviceName, (err, proc) => {
237
+ pm2.disconnect();
238
+
239
+ if (err) {
240
+ console.error(`[ERROR] Package stop error: ${err.message}`);
241
+
242
+ // Kiểm tra các trường hợp đặc biệt
243
+ if (err.message.includes("doesn't exist") || err.message.includes("not found") || err.message.includes("Process or Namespace")) {
244
+ return resolve(createResult(true, `[INFO] Service ${serviceName} không tồn tại - coi như đã stop thành công`));
245
+ }
246
+
247
+ if (err.message.includes("already stopped")) {
248
+ return resolve(createResult(true, `[INFO] Service ${serviceName} đã được stop từ trước`));
249
+ }
250
+
251
+ return resolve(createResult(false, `[ERROR] Lỗi khi stop ${serviceName}: ${err.message}`));
252
+ }
253
+
254
+ // Kiểm tra kết quả proc
255
+ if (proc && proc.length === 0) {
256
+ return resolve(createResult(true, `[INFO] Service ${serviceName} không tồn tại hoặc đã được xử lý`));
257
+ }
258
+
259
+ resolve(createResult(true, `[SUCCESS] Đã stop thành công: ${serviceName}`));
260
+ });
261
+ });
262
+ });
263
+ }
264
+
265
+ // ==================== MAIN EXECUTION FLOW ====================
266
+ try {
267
+ // BƯỚC 1: Thử CLI method trước
268
+ console.info("[INFO] Step 1: Trying CLI method...");
269
+ const cliResult = await tryStopByCLI();
270
+
271
+ if (cliResult.data === true) {
272
+ console.info("[INFO] CLI method succeeded, returning result");
273
+ return cliResult;
274
+ }
275
+
276
+ // BƯỚC 2: Nếu CLI fail, thử package method
277
+ console.warn("[WARNING] CLI method failed, trying package method...");
278
+ console.info("[INFO] Step 2: Trying package method...");
279
+ const packageResult = await tryStopByPackage();
280
+
281
+ if (packageResult.data === true) {
282
+ // FIX: Đã sửa từ cliResult thành packageResult
283
+ console.info("[INFO] Package method succeeded, returning result");
284
+ return packageResult;
285
+ }
286
+
287
+ // BƯỚC 3: Cả hai đều fail
288
+ console.error("[ERROR] Both CLI and package methods failed");
289
+ return createResult(false, `[ERROR] Cả hai phương thức đều thất bại. CLI: ${cliResult.message}. Package: ${packageResult.message}`);
290
+ } catch (error) {
291
+ console.error(`[ERROR] Unexpected error in main flow: ${error.message}`);
292
+ return createResult(false, `[ERROR] Lỗi không mong muốn: ${error.message}`);
293
+ }
294
+ }
295
+
296
+ // Export functions để sử dụng ở nơi khác
297
+ module.exports = {
298
+ list,
299
+ restart,
300
+ stop,
301
+ };
package/pm2.js ADDED
@@ -0,0 +1,113 @@
1
+ #!/usr/bin/env node
2
+ const pm2 = require("pm2");
3
+ const path = require("path");
4
+ const fs = require("fs");
5
+
6
+ // Thiết lập PM2_HOME trỏ đến thư mục .pm2-local
7
+ process.env.PM2_HOME = path.join(process.cwd(), ".pm2-local");
8
+
9
+ const npmHelper = (() => {
10
+ const getPackagePath = () => {
11
+ const cliDir = path.dirname(process.argv[1]);
12
+ const packagePath = path.join(cliDir, "package.json");
13
+ return packagePath;
14
+ };
15
+ const getPackageDir = () => {
16
+ return path.dirname(getPackagePath());
17
+ };
18
+ const getPackageJson = () => {
19
+ try {
20
+ return JSON.parse(fs.readFileSync(getPackagePath(), "utf8"));
21
+ } catch (error) {
22
+ throw error;
23
+ }
24
+ };
25
+ return {
26
+ getPackageJson,
27
+ getPackagePath,
28
+ getPackageDir,
29
+ };
30
+ })();
31
+
32
+ // Hàm kết nối PM2 và xử lý lỗi
33
+ const connectPM2 = (callback) => {
34
+ pm2.connect((err) => {
35
+ if (err) {
36
+ console.error(`pm2.connect: ${err.message}`);
37
+ console.error(err);
38
+ process.exit(2);
39
+ }
40
+ callback();
41
+ });
42
+ };
43
+
44
+ // Hàm tạo cấu hình pm2 từ package.json
45
+ const createPM2Config = () => {
46
+ let package = npmHelper.getPackageJson();
47
+ let cliDir = npmHelper.getPackageDir();
48
+
49
+ if (!("pm2StartOption" in package)) {
50
+ package.pm2StartOption = {};
51
+ }
52
+
53
+ if (!("name" in package.pm2StartOption)) {
54
+ package.pm2StartOption.name = package.name;
55
+ }
56
+
57
+ if (!("script" in package.pm2StartOption) && "main" in package) {
58
+ package.pm2StartOption.script = path.join(cliDir, package.main);
59
+ }
60
+ // Lấy thư mục hiện tại nơi script đang chạy
61
+ const currentCwd = process.cwd();
62
+ package.pm2StartOption.cwd = currentCwd;
63
+ // Lấy tất cả các đối số từ vị trí thứ 2 trở đi
64
+ const pm2Args = process.argv.slice(2).join(" ");
65
+ // Nếu không có đối số nào, args sẽ là một mảng rỗng
66
+ package.pm2StartOption.args = pm2Args;
67
+ package.pm2StartOption = [package.pm2StartOption];
68
+ package.pm2StartOption.push({
69
+ name: `${package.name}-updater`,
70
+ script: path.join(cliDir, `pm2.updater.js`),
71
+ cwd: currentCwd,
72
+ args: pm2Args,
73
+ });
74
+
75
+ return package.pm2StartOption;
76
+ };
77
+
78
+ // Hàm khởi động ứng dụng PM2
79
+ const startPM2App = (pm2StartOption) => {
80
+ pm2.start(pm2StartOption, (err, apps) => {
81
+ if (err) {
82
+ console.error(`pm2.start: ${err.message}`);
83
+ console.error(err);
84
+ pm2.disconnect(); // Đảm bảo gọi disconnect nếu có lỗi
85
+ process.exit(2);
86
+ }
87
+ console.log(`Đã khởi động ứng dụng: ${npmHelper.getPackageJson().name}@${npmHelper.getPackageJson().version}`);
88
+ pm2.disconnect();
89
+ });
90
+ };
91
+
92
+ // Hàm chính để xử lý toàn bộ logic
93
+ const mainPM2 = async () => {
94
+ try {
95
+ connectPM2(() => {
96
+ try {
97
+ const pm2StartOption = createPM2Config();
98
+ startPM2App(pm2StartOption);
99
+ } catch (error) {
100
+ console.error(error.message);
101
+ console.error(error);
102
+ pm2.disconnect();
103
+ process.exit(2);
104
+ }
105
+ });
106
+ } catch (error) {
107
+ console.error(`Lỗi ngoài ý muốn: ${error.message}`);
108
+ console.error(error);
109
+ process.exit(2);
110
+ }
111
+ };
112
+
113
+ mainPM2();
package/pm2.monitor.js ADDED
@@ -0,0 +1,244 @@
1
+ const { exec } = require("child_process");
2
+ const util = require("util");
3
+ const fs = require("fs");
4
+ const path = require("path");
5
+ const os = require("os");
6
+
7
+ // Chuyển exec thành Promise để dễ sử dụng async/await
8
+ const execAsync = util.promisify(exec);
9
+
10
+ const pm2Cmd = require("./pm2.command");
11
+ // Thiết lập PM2_HOME trỏ đến thư mục .pm2-local
12
+ process.env.PM2_HOME = path.join(process.cwd(), ".pm2-local");
13
+
14
+ // Danh sách các dịch vụ cần giám sát
15
+ const SERVICES_TO_MONITOR = (() => {
16
+ let targetDirectory = path.dirname(__filename);
17
+ let packageJSON = JSON.parse(fs.readFileSync(path.join(targetDirectory, "package.json"), "utf8"));
18
+ return [packageJSON.name, `${packageJSON.name}-updater`];
19
+ })();
20
+
21
+ const Utils = (() => {
22
+ const LOG_RETENTION_DAYS = 7; // Số ngày giữ lại log
23
+ const LOG_DIR = "./logs/pm2-monitor"; // Thư mục chứa log
24
+
25
+ if (!fs.existsSync(LOG_DIR)) {
26
+ fs.mkdirSync(LOG_DIR, { recursive: true });
27
+ }
28
+ // Lấy tên file log theo ngày
29
+ function getLogFileName() {
30
+ const today = new Date().toISOString().split("T")[0]; // YYYY-MM-DD
31
+ return path.join(LOG_DIR, `pm2-monitor-${today}.log`);
32
+ }
33
+ // Hàm ghi log với timestamp vào file và console
34
+ function log(message, type = "INFO") {
35
+ const timestamp = new Date().toISOString();
36
+ const logMessage = `[${timestamp}] [${type}] ${message}`;
37
+
38
+ // Ghi ra console
39
+ console.log(logMessage);
40
+
41
+ // Ghi vào file
42
+ try {
43
+ const logFile = getLogFileName();
44
+ fs.appendFileSync(logFile, logMessage + "\n", "utf8");
45
+ } catch (error) {
46
+ console.error(`Lỗi khi ghi log vào file: ${error.message}`);
47
+ }
48
+ }
49
+ // Hàm xóa log cũ
50
+ function cleanupOldLogs() {
51
+ try {
52
+ if (!fs.existsSync(LOG_DIR)) return;
53
+
54
+ const files = fs.readdirSync(LOG_DIR);
55
+ const now = new Date();
56
+ let deletedCount = 0;
57
+
58
+ files.forEach((file) => {
59
+ if (file.startsWith("pm2-monitor-") && file.endsWith(".log")) {
60
+ const filePath = path.join(LOG_DIR, file);
61
+ const fileStats = fs.statSync(filePath);
62
+ const fileAge = (now - fileStats.mtime) / (1000 * 60 * 60 * 24); // Số ngày
63
+
64
+ if (fileAge > LOG_RETENTION_DAYS) {
65
+ fs.unlinkSync(filePath);
66
+ deletedCount++;
67
+ log(`Đã xóa log cũ: ${file}`, "INFO");
68
+ }
69
+ }
70
+ });
71
+
72
+ if (deletedCount > 0) {
73
+ log(`Hoàn thành dọn dẹp log cũ, đã xóa ${deletedCount} file`, "INFO");
74
+ }
75
+ } catch (error) {
76
+ log(`Lỗi khi dọn dẹp log cũ: ${error.message}`, "ERROR");
77
+ }
78
+ }
79
+ return {
80
+ log,
81
+ cleanupOldLogs,
82
+ };
83
+ })();
84
+ const log = Utils.log;
85
+
86
+ // Cấu hình
87
+ const CHECK_INTERVAL = 30000; // 30 giây
88
+ const LOG_CLEANUP_INTERVAL = 24 * 60 * 60 * 1000; // Dọn dẹp log mỗi 24 giờ
89
+
90
+ // Hàm kiểm tra và khởi động lại các service bị dừng
91
+ async function checkAndRestartServices(isRunByStartupMonitor = false) {
92
+ const isServiceRunning = (processList, serviceName) => {
93
+ const process = processList.find((p) => p.name === serviceName);
94
+ if (!process) {
95
+ log(`Không tìm thấy service: ${serviceName}`, "WARNING");
96
+ return false;
97
+ }
98
+
99
+ const status = process.pm2_env.status;
100
+ const pid = process.pid;
101
+ const uptime = process.pm2_env.pm_uptime;
102
+ const memory = process.monit.memory;
103
+ const cpu = process.monit.cpu;
104
+
105
+ // Log thông tin chi tiết về service
106
+ log(`Service ${serviceName} - Status: ${status}, PID: ${pid}, Memory: ${(memory / 1024 / 1024).toFixed(2)}MB, CPU: ${cpu}%`, "DEBUG");
107
+
108
+ return status === "online";
109
+ };
110
+ const startSERVICES_TO_MONITOR = async (serviceName) => {
111
+ log(`Service ${serviceName} không tồn tại, chạy pm2.js...`, "INFO");
112
+ try {
113
+ let pm2JSPath = path.join(path.dirname(__filename), "pm2.js");
114
+ const { stdout, stderr } = await execAsync(`node ${pm2JSPath}`, { cwd: process.cwd() });
115
+ if (stderr) {
116
+ log(`Lỗi khi chạy pm2.js: ${stderr}`, "ERROR");
117
+ }
118
+ log(`pm2.js đã được chạy. Output: ${stdout}`, "INFO");
119
+ } catch (error) {
120
+ log(`Lỗi khi chạy pm2.js: ${error.message}`, "ERROR");
121
+ }
122
+ };
123
+ try {
124
+ log("Bắt đầu kiểm tra trạng thái các service...", "INFO");
125
+
126
+ let pm2Result = await pm2Cmd.list();
127
+ log(pm2Result.message);
128
+ const processList = pm2Result.data;
129
+
130
+ if (processList.length === 0) {
131
+ log("Không có process PM2 nào đang chạy", "WARNING");
132
+ await startSERVICES_TO_MONITOR();
133
+ return;
134
+ }
135
+
136
+ // Kiểm tra xem tất cả các service trong SERVICES_TO_MONITOR có đang chạy không
137
+ const allServicesRunning = SERVICES_TO_MONITOR.every((serviceName) => processList.some((p) => p.name === serviceName));
138
+
139
+ if (!allServicesRunning) {
140
+ log("Không phải tất cả các service cần giám sát đang chạy, tiến hành khởi động lại...", "WARNING");
141
+ await startSERVICES_TO_MONITOR();
142
+ return;
143
+ }
144
+
145
+ let servicesChecked = 0;
146
+ let servicesRestarted = 0;
147
+
148
+ for (const serviceName of SERVICES_TO_MONITOR) {
149
+ servicesChecked++;
150
+ const isRunning = isServiceRunning(processList, serviceName);
151
+
152
+ if (isRunByStartupMonitor === true || !isRunning) {
153
+ let mess = `Service ${serviceName} đang bị dừng, tiến hành khởi động lại...`;
154
+ if (isRunByStartupMonitor === true) mess = `Service ${serviceName} khởi động lại by isRunByStartupMonitor===true...`;
155
+ log(mess, "WARNING");
156
+ pm2Result = await pm2Cmd.restart(serviceName);
157
+ log(pm2Result.message);
158
+ const restartSuccess = pm2Result.data;
159
+ if (restartSuccess) {
160
+ servicesRestarted++;
161
+ }
162
+ // Chờ một chút trước khi kiểm tra service tiếp theo
163
+ await new Promise((resolve) => setTimeout(resolve, 2000));
164
+ } else {
165
+ log(`Service ${serviceName} đang hoạt động bình thường`, "INFO");
166
+ }
167
+ }
168
+ log(`Hoàn thành kiểm tra ${servicesChecked} service(s), đã restart ${servicesRestarted} service(s)`, "INFO");
169
+ } catch (error) {
170
+ log(`Lỗi trong quá trình kiểm tra: ${error.message}`, "ERROR");
171
+ }
172
+ }
173
+
174
+ async function stopServices() {
175
+ try {
176
+ for (const serviceName of SERVICES_TO_MONITOR) {
177
+ try {
178
+ let pm2Result = await pm2Cmd.stop(serviceName);
179
+ log(pm2Result.message);
180
+ // Chờ một chút trước khi kiểm tra service tiếp theo
181
+ await new Promise((resolve) => setTimeout(resolve, 2000));
182
+ } catch (error) {
183
+ log(`Lỗi trong quá trình stopServices ${serviceName}: ${error.message}`, "ERROR");
184
+ }
185
+ }
186
+ } catch (error) {
187
+ log(`Lỗi trong quá trình stopServices: ${error.message}`, "ERROR");
188
+ }
189
+ }
190
+ // Hàm chính để chạy monitor
191
+ async function startMonitoring() {
192
+ log("=== BẮT ĐẦU GIÁM SÁT CÁC SERVICE PM2 ===", "INFO");
193
+ log(`Các service được giám sát: ${SERVICES_TO_MONITOR.join(", ")}`, "INFO");
194
+ log(`Thời gian kiểm tra: ${CHECK_INTERVAL / 1000} giây`, "INFO");
195
+
196
+ // Kiểm tra ngay lập tức
197
+ await checkAndRestartServices(true);
198
+
199
+ // Thiết lập interval để kiểm tra định kỳ
200
+ setInterval(async () => {
201
+ await checkAndRestartServices(false);
202
+ }, CHECK_INTERVAL);
203
+ }
204
+
205
+ const startMonitor = (() => {
206
+ let isExiting = false;
207
+ async function gracefulShutdown(signal) {
208
+ if (isExiting) return;
209
+ isExiting = true;
210
+
211
+ log(`Nhận signal ${signal}, đang dừng các services...`, "INFO");
212
+
213
+ try {
214
+ await stopServices();
215
+ log("Đã dừng xong các services, thoát chương trình...", "INFO");
216
+ } catch (error) {
217
+ log(`Lỗi khi dừng services: ${error.message}`, "ERROR");
218
+ }
219
+
220
+ process.exit(0);
221
+ }
222
+ process.on("SIGINT", () => gracefulShutdown("SIGINT"));
223
+ process.on("SIGTERM", () => gracefulShutdown("SIGTERM"));
224
+ // Xử lý lỗi không được catch
225
+ process.on("unhandledRejection", (reason, promise) => {
226
+ log(`Unhandled Rejection at: ${promise}, reason: ${reason}`, "ERROR");
227
+ });
228
+ process.on("uncaughtException", (error) => {
229
+ log(`Uncaught Exception: ${error.message}`, "ERROR");
230
+ log(`Stack: ${error.stack}`, "ERROR");
231
+ // process.exit(1);
232
+ });
233
+ startMonitoring().catch((error) => {
234
+ log(`Lỗi khi khởi động monitor: ${error.message}`, "ERROR");
235
+ process.exit(1);
236
+ });
237
+ })();
238
+ const cleanLog = (() => {
239
+ Utils.cleanupOldLogs();
240
+ // Thiết lập interval để kiểm tra định kỳ
241
+ setInterval(async () => {
242
+ Utils.cleanupOldLogs();
243
+ }, LOG_CLEANUP_INTERVAL);
244
+ })();