فهرست منبع

fix: graceful shutdown (#3821)

* fix: missing graceful shutdown handler

* fix: asar - use async fs operation

* fix: scheduler - graceful shutdown and wait for running jobs to complete
LK HO 4 سال پیش
والد
کامیت
a103127545
4فایلهای تغییر یافته به همراه39 افزوده شده و 23 حذف شده
  1. 4 4
      server/core/asar.js
  2. 10 8
      server/core/kernel.js
  3. 12 11
      server/core/scheduler.js
  4. 13 0
      server/index.js

+ 4 - 4
server/core/asar.js

@@ -40,11 +40,11 @@ module.exports = {
     }
   },
   async unload () {
-    if (this.fdCache) {
+    const fds = Object.values(this.fdCache)
+    if (fds.length > 0) {
       WIKI.logger.info('Closing ASAR file descriptors...')
-      for (const fdItem in this.fdCache) {
-        fs.closeSync(this.fdCache[fdItem].fd)
-      }
+      const closeAsync = require('util').promisify(fs.close)
+      await Promise.all(fds.map(x => closeAsync(x.fd)))
       this.fdCache = {}
     }
   },

+ 10 - 8
server/core/kernel.js

@@ -107,19 +107,21 @@ module.exports = {
    * Graceful shutdown
    */
   async shutdown () {
-    if (WIKI.models) {
-      await WIKI.models.unsubscribeToNotifications()
-      await WIKI.models.knex.client.pool.destroy()
-      await WIKI.models.knex.destroy()
+    if (WIKI.servers) {
+      await WIKI.servers.stopServers()
     }
     if (WIKI.scheduler) {
-      WIKI.scheduler.stop()
+      await WIKI.scheduler.stop()
+    }
+    if (WIKI.models) {
+      await WIKI.models.unsubscribeToNotifications()
+      if (WIKI.models.knex) {
+        await WIKI.models.knex.destroy()
+      }
     }
     if (WIKI.asar) {
       await WIKI.asar.unload()
     }
-    if (WIKI.servers) {
-      await WIKI.servers.stopServers()
-    }
+    process.exit(0)
   }
 }

+ 12 - 11
server/core/scheduler.js

@@ -12,7 +12,8 @@ class Job {
     schedule = 'P1D',
     repeat = false,
     worker = false
-  }) {
+  }, queue) {
+    this.queue = queue
     this.finished = Promise.resolve()
     this.name = name
     this.immediate = immediate
@@ -27,6 +28,7 @@ class Job {
    * @param {Object} data Job Data
    */
   start(data) {
+    this.queue.jobs.push(this)
     if (this.immediate) {
       this.invoke(data)
     } else {
@@ -82,16 +84,20 @@ class Job {
     } catch (err) {
       WIKI.logger.warn(err)
     }
-    if (this.repeat) {
+    if (this.repeat && this.queue.jobs.includes(this)) {
       this.queue(data)
+    } else {
+      this.stop().catch(() => {})
     }
   }
 
   /**
    * Stop any future job invocation from occuring
    */
-  stop() {
+  async stop() {
     clearTimeout(this.timeout)
+    this.queue.jobs = this.queue.jobs.filter(x => x !== this)
+    return this.finished
   }
 }
 
@@ -118,16 +124,11 @@ module.exports = {
     })
   },
   registerJob(opts, data) {
-    const job = new Job(opts)
+    const job = new Job(opts, this)
     job.start(data)
-    if (job.repeat) {
-      this.jobs.push(job)
-    }
     return job
   },
-  stop() {
-    this.jobs.forEach(job => {
-      job.stop()
-    })
+  async stop() {
+    return Promise.all(this.jobs.map(job => job.stop()))
   }
 }

+ 13 - 0
server/index.js

@@ -33,3 +33,16 @@ WIKI.logger = require('./core/logger').init('MASTER')
 // ----------------------------------------
 
 WIKI.kernel.init()
+
+// ----------------------------------------
+// Register exit handler
+// ----------------------------------------
+
+process.on('SIGINT', () => {
+  WIKI.kernel.shutdown()
+})
+process.on('message', (msg) => {
+  if (msg === 'shutdown') {
+    WIKI.kernel.shutdown()
+  }
+})