microship 1.0.0 → 1.0.1
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.
- package/README.md +1 -3
- package/package.json +1 -1
- package/src/index.js +7 -26
- package/src/status.js +2 -2
- package/src/worker.js +1 -1
package/README.md
CHANGED
|
@@ -4,8 +4,6 @@ Readiness, liveness, and graceful shutdown for a Node process on Kubernetes.
|
|
|
4
4
|
|
|
5
5
|
`/ready` and `/live` run on a [worker thread](https://nodejs.org/api/worker_threads.html). A busy event loop stays ready. `/live` returns 500 after the loop has not run for 15 seconds. Shutdown marks the process not ready, waits `shutdownDelay` so the kubelet observes it, runs the shutdown handler, then exits.
|
|
6
6
|
|
|
7
|
-
Outside Kubernetes the probe binds a random port, so a local process does not take 3001.
|
|
8
|
-
|
|
9
7
|
```js
|
|
10
8
|
const { createMicroship } = require('microship')
|
|
11
9
|
|
|
@@ -23,4 +21,4 @@ ship.registerShutdownHandler(async () => {
|
|
|
23
21
|
ship.signalReady()
|
|
24
22
|
```
|
|
25
23
|
|
|
26
|
-
`shutdownHandlerTimeout` forces `terminate` when the handler does not finish. Signals are `SIGTERM
|
|
24
|
+
`shutdownHandlerTimeout` forces `terminate` when the handler does not finish. Signals are `SIGTERM` and `SIGINT`.
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "microship",
|
|
3
3
|
"description": "Readiness, liveness, and graceful shutdown for a Node process on Kubernetes.",
|
|
4
4
|
"homepage": "https://github.com/Kikobeats/microship",
|
|
5
|
-
"version": "1.0.
|
|
5
|
+
"version": "1.0.1",
|
|
6
6
|
"main": "src/index.js",
|
|
7
7
|
"author": {
|
|
8
8
|
"email": "josefrancisco.verdu@gmail.com",
|
package/src/index.js
CHANGED
|
@@ -3,28 +3,17 @@
|
|
|
3
3
|
const { Worker } = require('worker_threads')
|
|
4
4
|
const path = require('path')
|
|
5
5
|
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
const SIGNALS = ['SIGTERM', 'SIGHUP', 'SIGINT']
|
|
6
|
+
const SIGNALS = ['SIGTERM', 'SIGINT']
|
|
9
7
|
const EXIT_DELAY = 1000
|
|
10
8
|
|
|
11
9
|
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
|
|
12
10
|
|
|
13
|
-
const inKubernetes = () => Boolean(process.env.KUBERNETES_SERVICE_HOST)
|
|
14
|
-
|
|
15
11
|
const createMicroship = async ({
|
|
16
|
-
detectKubernetes = true,
|
|
17
12
|
port = 3001,
|
|
18
|
-
shutdownDelay,
|
|
13
|
+
shutdownDelay = 1000,
|
|
19
14
|
shutdownHandlerTimeout = 5000,
|
|
20
|
-
signals = SIGNALS,
|
|
21
|
-
staleMs = STALE_MS,
|
|
22
15
|
terminate = () => process.exit(0)
|
|
23
16
|
} = {}) => {
|
|
24
|
-
const local = detectKubernetes && !inKubernetes()
|
|
25
|
-
const probePort = local ? 0 : port
|
|
26
|
-
const delay = shutdownDelay === undefined ? (local ? 0 : 5000) : shutdownDelay
|
|
27
|
-
|
|
28
17
|
let ready = false
|
|
29
18
|
let shuttingDown = false
|
|
30
19
|
const handlers = []
|
|
@@ -36,7 +25,7 @@ const createMicroship = async ({
|
|
|
36
25
|
}
|
|
37
26
|
|
|
38
27
|
const worker = new Worker(path.join(__dirname, 'worker.js'), {
|
|
39
|
-
workerData: { port
|
|
28
|
+
workerData: { port, sab: view.buffer }
|
|
40
29
|
})
|
|
41
30
|
worker.unref()
|
|
42
31
|
|
|
@@ -60,17 +49,12 @@ const createMicroship = async ({
|
|
|
60
49
|
publish()
|
|
61
50
|
}
|
|
62
51
|
|
|
63
|
-
const signalNotReady = () => {
|
|
64
|
-
ready = false
|
|
65
|
-
publish()
|
|
66
|
-
}
|
|
67
|
-
|
|
68
52
|
const shutdown = async () => {
|
|
69
53
|
if (shuttingDown) return
|
|
70
54
|
ready = false
|
|
71
55
|
shuttingDown = true
|
|
72
56
|
publish()
|
|
73
|
-
if (
|
|
57
|
+
if (shutdownDelay) await sleep(shutdownDelay)
|
|
74
58
|
|
|
75
59
|
let forced = false
|
|
76
60
|
const timer = setTimeout(() => {
|
|
@@ -90,24 +74,21 @@ const createMicroship = async ({
|
|
|
90
74
|
const onSignal = () => {
|
|
91
75
|
shutdown().catch(() => {})
|
|
92
76
|
}
|
|
93
|
-
for (const signal of
|
|
77
|
+
for (const signal of SIGNALS) process.on(signal, onSignal)
|
|
94
78
|
|
|
95
79
|
return {
|
|
96
80
|
port: bound,
|
|
97
|
-
isServerReady: () => ready && !shuttingDown,
|
|
98
|
-
isServerShuttingDown: () => shuttingDown,
|
|
99
81
|
registerShutdownHandler: handler => {
|
|
100
82
|
handlers.push(handler)
|
|
101
83
|
},
|
|
102
84
|
shutdown,
|
|
103
|
-
signalNotReady,
|
|
104
85
|
signalReady,
|
|
105
86
|
stop: async () => {
|
|
106
87
|
clearInterval(beat)
|
|
107
|
-
for (const signal of
|
|
88
|
+
for (const signal of SIGNALS) process.off(signal, onSignal)
|
|
108
89
|
await worker.terminate()
|
|
109
90
|
}
|
|
110
91
|
}
|
|
111
92
|
}
|
|
112
93
|
|
|
113
|
-
module.exports = { createMicroship
|
|
94
|
+
module.exports = { createMicroship }
|
package/src/status.js
CHANGED
|
@@ -13,10 +13,10 @@ const beatAge = (view, state, now) => {
|
|
|
13
13
|
return now - state.lastBeatAt
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
const statusFor = (view, state, url, now
|
|
16
|
+
const statusFor = (view, state, url, now) => {
|
|
17
17
|
const shuttingDown = Atomics.load(view, 1) === 1
|
|
18
18
|
const ready = Atomics.load(view, 0) === 1 && !shuttingDown
|
|
19
|
-
const live = !shuttingDown && beatAge(view, state, now) <
|
|
19
|
+
const live = !shuttingDown && beatAge(view, state, now) < STALE_MS
|
|
20
20
|
if (url === '/live') return live ? 200 : 500
|
|
21
21
|
if (url === '/ready') return ready ? 200 : 500
|
|
22
22
|
return 404
|
package/src/worker.js
CHANGED
|
@@ -10,7 +10,7 @@ const state = createState()
|
|
|
10
10
|
|
|
11
11
|
const server = http.createServer((req, res) => {
|
|
12
12
|
const url = (req.url || '/').split('?')[0]
|
|
13
|
-
const code = statusFor(view, state, url, Date.now()
|
|
13
|
+
const code = statusFor(view, state, url, Date.now())
|
|
14
14
|
res.writeHead(code, { 'content-type': 'text/plain' })
|
|
15
15
|
res.end()
|
|
16
16
|
})
|