1
0

2 Коммиты 86ab929eba ... 8c08b0c519

Автор SHA1 Сообщение Дата
  yangkaixiang 8c08b0c519 feat(core): 实现优雅停机以正确释放资源 6 дней назад
  yangkaixiang b5fbed46e7 build(docker): 移除冗余的data目录创建指令 6 дней назад
4 измененных файлов с 44 добавлено и 5 удалено
  1. 0 2
      Dockerfile
  2. 30 2
      src/index.js
  3. 13 0
      src/mqttService.js
  4. 1 1
      src/scheduler.js

+ 0 - 2
Dockerfile

@@ -14,8 +14,6 @@ COPY views ./views
 COPY public ./public
 COPY DESIGN.md ./DESIGN.md
 
-RUN mkdir -p /app/data
-
 EXPOSE 3000
 
 CMD ["node", "src/index.js"]

+ 30 - 2
src/index.js

@@ -218,10 +218,38 @@ app.post('/settings', (req, res) => {
 
 cleanupLogs();
 mqttService.connect();
-startScheduler(mqttService);
+const schedulerTask = startScheduler(mqttService);
 
 const config = getConfig();
 const port = Number(process.env.PORT || config.server_port || 3000);
-app.listen(port, () => {
+const server = app.listen(port, () => {
   console.log(`Office Light running at http://localhost:${port}`);
 });
+
+let shuttingDown = false;
+
+async function shutdown(signal) {
+  if (shuttingDown) return;
+  shuttingDown = true;
+  console.log(`Received ${signal}, shutting down...`);
+
+  schedulerTask.stop();
+
+  await new Promise((resolve) => {
+    server.close(resolve);
+  });
+
+  await mqttService.close();
+  db.close();
+  process.exit(0);
+}
+
+process.on('SIGTERM', () => shutdown('SIGTERM').catch((error) => {
+  console.error('Shutdown failed:', error);
+  process.exit(1);
+}));
+
+process.on('SIGINT', () => shutdown('SIGINT').catch((error) => {
+  console.error('Shutdown failed:', error);
+  process.exit(1);
+}));

+ 13 - 0
src/mqttService.js

@@ -85,6 +85,19 @@ class MqttService {
     return this.status;
   }
 
+  close() {
+    if (!this.client) return Promise.resolve();
+
+    const client = this.client;
+    this.client = null;
+    this.pending.clear();
+    this.status = { connected: false, message: '连接已关闭', lastError: null, connectedAt: null };
+
+    return new Promise((resolve) => {
+      client.end(false, {}, resolve);
+    });
+  }
+
   commandTopic(channel) {
     const topicConfig = getTopicConfig();
     return `${topicConfig.commandPrefix}/Power${channel}`;

+ 1 - 1
src/scheduler.js

@@ -4,7 +4,7 @@ const { db, getConfig } = require('./db');
 const { getDueSchedules } = require('./scheduleService');
 
 function startScheduler(mqttService) {
-  cron.schedule('* * * * *', async () => {
+  return cron.schedule('* * * * *', async () => {
     await runDueSchedules(mqttService);
     cleanupLogs();
   });