1 | # Copacetic
|
2 | [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com)
|
3 | [![Coverage Status](https://coveralls.io/repos/github/fresh8/copacetic/badge.svg?branch=master)](https://coveralls.io/github/fresh8/copacetic?branch=master)
|
4 | [![CircleCI](https://circleci.com/gh/fresh8/copacetic.svg?style=svg)](https://circleci.com/gh/fresh8/copacetic)
|
5 |
|
6 | A package to help your service check the health of its dependencies.
|
7 |
|
8 |
|
9 | ## Requirements
|
10 | Node v6.4.0 and above
|
11 |
|
12 | ## Installation
|
13 | ```
|
14 | npm install @fresh8/copacetic --save
|
15 | ```
|
16 |
|
17 | #### Quick Start - Javascript
|
18 | ```javascript
|
19 | const Copacetic = require('@fresh8/copacetic')
|
20 | const level = require('@fresh8/copacetic').dependencyLevel
|
21 |
|
22 | const copacetic = Copacetic()
|
23 |
|
24 | // Register a dependency
|
25 | copacetic.registerDependency({
|
26 | name: 'My-Dependency',
|
27 | url: 'https://my-Dependency.io',
|
28 | // Defaults to SOFT
|
29 | level: level.HARD
|
30 | })
|
31 |
|
32 |
|
33 | // Check its health
|
34 | copacetic
|
35 | .check({
|
36 | name: 'My-Dependency',
|
37 | retries: 2
|
38 | })
|
39 | .on('healthy', (Dependency) => {
|
40 | /**
|
41 | * { name: 'My-Dependency',
|
42 | * healthy: true/false,
|
43 | * lastChecked: Date,
|
44 | * level: 'SOFT'
|
45 | * }
|
46 | */
|
47 | })
|
48 | .on('unhealthy', (Dependency) => {
|
49 | // Handle degraded state...
|
50 | })
|
51 |
|
52 | // in promise mode
|
53 | copacetic.eventEmitterMode = false
|
54 |
|
55 | copacetic
|
56 | .check({ name: 'my-web-service' })
|
57 | .then((res) => {
|
58 | console.log(`${res.name} is healthy!`)
|
59 | })
|
60 | .catch((err) => {
|
61 | console.log(err)
|
62 | })
|
63 | ```
|
64 |
|
65 | #### Quick Start - Typescript
|
66 | ```typescript
|
67 | import * as Copacetic from '@fresh8/copacetic'
|
68 |
|
69 | const copacetic = Copacetic('my-service')
|
70 |
|
71 | const myDependencyOverHttp : Copacetic.DependencyOptions = {
|
72 | name: 'my-web-service',
|
73 | url: 'http://example.com'
|
74 | }
|
75 |
|
76 | copacetic.registerDependency(myDependencyOverHttp)
|
77 |
|
78 | instance
|
79 | .check({ name: 'my-web-service' })
|
80 | .on('healthy', (res: Copacetic.Health) => {
|
81 | // do something with your healthy dependency :)
|
82 | })
|
83 | .on('unhealthy', (res: Copacetic.Health) => {
|
84 | // handle degraded state
|
85 | })
|
86 |
|
87 | // in promise mode
|
88 | copacetic.eventEmitterMode = false
|
89 |
|
90 | async function waitForWebService () {
|
91 | try {
|
92 | const res = await instance
|
93 | .check<Copacetic.Health>({ name: 'my-web-service' })
|
94 |
|
95 | console.log(`${res.name} is healthy!`)
|
96 | } catch (err) {
|
97 | console.log(err)
|
98 | }
|
99 | }
|
100 | ```
|
101 |
|
102 | #### Quick Start - cluster mode
|
103 | ```js
|
104 |
|
105 | const Copacetic = require('@fresh8/copacetic')
|
106 | const level = require('@fresh8/copacetic').dependencyLevel
|
107 |
|
108 | const copacetic = Copacetic("A name", false)
|
109 |
|
110 | Copacetic.cluster.attach(copacetic)
|
111 |
|
112 | if (process.worker) {
|
113 | //register your usual dependencies like databases
|
114 |
|
115 |
|
116 | //use the line below to have the worker ask the master process a full health report
|
117 | copacetic.checkCluster() //`checkCluster` is only defined if the process is a worker and if you called `attach()`
|
118 | .then(console.log)
|
119 | } else {
|
120 | copacetic.checkAll()
|
121 | .then(() => {
|
122 | console.log(copacetic.healthReport) //Contains health information as reported by the workers
|
123 | })
|
124 | }
|
125 | ```
|
126 |
|
127 | ## Classes
|
128 |
|
129 | <dl>
|
130 | <dt><a href="#Copacetic">Copacetic</a> ⇐ <code>EventEmitter</code></dt>
|
131 | <dd></dd>
|
132 | </dl>
|
133 |
|
134 | ## Typedefs
|
135 |
|
136 | <dl>
|
137 | <dt><a href="#HealthReport">HealthReport</a> : <code>Object</code></dt>
|
138 | <dd><p>The full health report including isHealthy and dependencies</p>
|
139 | </dd>
|
140 | </dl>
|
141 |
|
142 | <a name="Copacetic"></a>
|
143 |
|
144 | ## Copacetic ⇐ <code>EventEmitter</code>
|
145 | **Kind**: global class
|
146 | **Extends**: <code>EventEmitter</code>
|
147 |
|
148 | * [Copacetic](#Copacetic) ⇐ <code>EventEmitter</code>
|
149 | * [new Copacetic([name])](#new_Copacetic_new)
|
150 | * [.isHealthy](#Copacetic+isHealthy) ⇒ <code>Boolean</code>
|
151 | * [.healthInfo](#Copacetic+healthInfo) ⇒ <code>Array.<DependencyHealth></code>
|
152 | * [.healthReport](#Copacetic+healthReport) ⇒ [<code>HealthReport</code>](#HealthReport)
|
153 | * [.getDependency(dependency)](#Copacetic+getDependency) ⇒ <code>Dependency</code>
|
154 | * [.isDependencyRegistered(dependency)](#Copacetic+isDependencyRegistered) ⇒ <code>Boolean</code>
|
155 | * [.registerDependency(opts)](#Copacetic+registerDependency) ⇒ [<code>Copacetic</code>](#Copacetic)
|
156 | * [.deregisterDependency(name)](#Copacetic+deregisterDependency) ⇒ [<code>Copacetic</code>](#Copacetic)
|
157 | * [.pollAll([interval], [parallel], [schedule])](#Copacetic+pollAll) ⇒ [<code>Copacetic</code>](#Copacetic)
|
158 | * [.poll([name], [dependencies], [interval], [parallel], [schedule])](#Copacetic+poll) ⇒ [<code>Copacetic</code>](#Copacetic)
|
159 | * [.stop()](#Copacetic+stop)
|
160 | * [.checkAll([parallel])](#Copacetic+checkAll) ⇒ [<code>Copacetic</code>](#Copacetic)
|
161 | * [.check([name], [dependencies], [retries], [parallel])](#Copacetic+check) ⇒ [<code>Copacetic</code>](#Copacetic)
|
162 | * [.waitFor(opts)](#Copacetic+waitFor)
|
163 | * [._checkOne(name, maxDelay)](#Copacetic+_checkOne) ⇒ <code>Promise</code>
|
164 | * [._checkMany(dependencies, parallel)](#Copacetic+_checkMany) ⇒ <code>Promise</code>
|
165 | * ["healthy"](#Copacetic+event_healthy)
|
166 | * ["unhealthy"](#Copacetic+event_unhealthy)
|
167 | * ["health"](#Copacetic+event_health)
|
168 |
|
169 | <a name="new_Copacetic_new"></a>
|
170 |
|
171 | ### new Copacetic([name])
|
172 |
|
173 | | Param | Type | Default | Description |
|
174 | | --- | --- | --- | --- |
|
175 | | [name] | <code>String</code> | <code>''</code> | The name of your service |
|
176 |
|
177 | <a name="Copacetic+isHealthy"></a>
|
178 |
|
179 | ### copacetic.isHealthy ⇒ <code>Boolean</code>
|
180 | **Kind**: instance property of [<code>Copacetic</code>](#Copacetic)
|
181 | **Returns**: <code>Boolean</code> - Copacetic is healthy when all hard dependencies are healthy
|
182 | <a name="Copacetic+healthInfo"></a>
|
183 |
|
184 | ### copacetic.healthInfo ⇒ <code>Array.<DependencyHealth></code>
|
185 | **Kind**: instance property of [<code>Copacetic</code>](#Copacetic)
|
186 | **Returns**: <code>Array.<DependencyHealth></code> - Health information on all dependencies
|
187 | <a name="Copacetic+healthReport"></a>
|
188 |
|
189 | ### copacetic.healthReport ⇒ [<code>HealthReport</code>](#HealthReport)
|
190 | **Kind**: instance property of [<code>Copacetic</code>](#Copacetic)
|
191 | **Returns**: [<code>HealthReport</code>](#HealthReport) - A full report of health information and dependencies
|
192 | <a name="Copacetic+getDependency"></a>
|
193 |
|
194 | ### copacetic.getDependency(dependency) ⇒ <code>Dependency</code>
|
195 | **Kind**: instance method of [<code>Copacetic</code>](#Copacetic)
|
196 |
|
197 | | Param | Type |
|
198 | | --- | --- |
|
199 | | dependency | <code>Dependency</code> \| <code>String</code> |
|
200 |
|
201 | <a name="Copacetic+isDependencyRegistered"></a>
|
202 |
|
203 | ### copacetic.isDependencyRegistered(dependency) ⇒ <code>Boolean</code>
|
204 | **Kind**: instance method of [<code>Copacetic</code>](#Copacetic)
|
205 | **Returns**: <code>Boolean</code> - Whether the dependency has been registered
|
206 |
|
207 | | Param | Type |
|
208 | | --- | --- |
|
209 | | dependency | <code>Dependency</code> \| <code>String</code> |
|
210 |
|
211 | <a name="Copacetic+registerDependency"></a>
|
212 |
|
213 | ### copacetic.registerDependency(opts) ⇒ [<code>Copacetic</code>](#Copacetic)
|
214 | Adds a dependency to a Copacetic instance
|
215 |
|
216 | **Kind**: instance method of [<code>Copacetic</code>](#Copacetic)
|
217 |
|
218 | | Param | Type | Description |
|
219 | | --- | --- | --- |
|
220 | | opts | <code>Object</code> | The configuration for a dependency |
|
221 |
|
222 | <a name="Copacetic+deregisterDependency"></a>
|
223 |
|
224 | ### copacetic.deregisterDependency(name) ⇒ [<code>Copacetic</code>](#Copacetic)
|
225 | Removes a dependency from a Copacetic instance
|
226 |
|
227 | **Kind**: instance method of [<code>Copacetic</code>](#Copacetic)
|
228 |
|
229 | | Param | Type | Description |
|
230 | | --- | --- | --- |
|
231 | | name | <code>String</code> | The name used to identify a dependency |
|
232 |
|
233 | <a name="Copacetic+pollAll"></a>
|
234 |
|
235 | ### copacetic.pollAll([interval], [parallel], [schedule]) ⇒ [<code>Copacetic</code>](#Copacetic)
|
236 | Polls the health of all registered dependencies
|
237 |
|
238 | **Kind**: instance method of [<code>Copacetic</code>](#Copacetic)
|
239 |
|
240 | | Param | Type | Default |
|
241 | | --- | --- | --- |
|
242 | | [interval] | <code>String</code> | <code>'5 seconds'</code> |
|
243 | | [parallel] | <code>Boolean</code> | <code>true</code> |
|
244 | | [schedule] | <code>String</code> | <code>'start'</code> |
|
245 |
|
246 | <a name="Copacetic+poll"></a>
|
247 |
|
248 | ### copacetic.poll([name], [dependencies], [interval], [parallel], [schedule]) ⇒ [<code>Copacetic</code>](#Copacetic)
|
249 | Polls the health of a set of dependencies
|
250 |
|
251 | **Kind**: instance method of [<code>Copacetic</code>](#Copacetic)
|
252 | **Emits**: [<code>health</code>](#Copacetic+event_health)
|
253 |
|
254 | | Param | Type | Default | Description |
|
255 | | --- | --- | --- | --- |
|
256 | | [name] | <code>String</code> | | The identifier of a single dependency to be checked |
|
257 | | [dependencies] | <code>Array.<Object></code> | | An explicit set of dependencies to be polled |
|
258 | | [interval] | <code>String</code> | <code>'5 seconds'</code> | |
|
259 | | [parallel] | <code>Boolean</code> | <code>true</code> | Kick of health checks in parallel or series |
|
260 | | [schedule] | <code>String</code> | <code>'start'</code> | Schedule the next check to start (interval - ms) | ms |
|
261 |
|
262 | **Example**
|
263 | ```js
|
264 | copacetic.poll({
|
265 | dependencies: [
|
266 | { name: 'my-dep' },
|
267 | { name: 'my-other-dep', retries: 2, maxDelay: '2 seconds' }
|
268 | ],
|
269 | schedule: 'end',
|
270 | interval: '1 minute 30 seconds'
|
271 | })
|
272 | .on('health', (serviceHealth, stop) => {
|
273 | // Do something with the result
|
274 | // [{ name: String, health: Boolean, level: HARD/SOFT, lastCheck: Date }]
|
275 | // stop polling
|
276 | stop()
|
277 | })
|
278 | ```
|
279 | **Example**
|
280 | ```js
|
281 | copacetic.poll({ name: 'my-dependency' })
|
282 | .on('health', () => { ... Do something })
|
283 | ```
|
284 | <a name="Copacetic+stop"></a>
|
285 |
|
286 | ### copacetic.stop()
|
287 | stops polling registered dependencies
|
288 |
|
289 | **Kind**: instance method of [<code>Copacetic</code>](#Copacetic)
|
290 | <a name="Copacetic+checkAll"></a>
|
291 |
|
292 | ### copacetic.checkAll([parallel]) ⇒ [<code>Copacetic</code>](#Copacetic)
|
293 | Checks the health of all registered dependencies
|
294 |
|
295 | **Kind**: instance method of [<code>Copacetic</code>](#Copacetic)
|
296 |
|
297 | | Param | Type | Default | Description |
|
298 | | --- | --- | --- | --- |
|
299 | | [parallel] | <code>Boolean</code> | <code>true</code> | Kick of health checks in parallel or series |
|
300 |
|
301 | <a name="Copacetic+check"></a>
|
302 |
|
303 | ### copacetic.check([name], [dependencies], [retries], [parallel]) ⇒ [<code>Copacetic</code>](#Copacetic)
|
304 | Checks the health of a set, or single dependency
|
305 |
|
306 | **Kind**: instance method of [<code>Copacetic</code>](#Copacetic)
|
307 | **Emits**: [<code>health</code>](#Copacetic+event_health), [<code>healthy</code>](#Copacetic+event_healthy), [<code>unhealthy</code>](#Copacetic+event_unhealthy)
|
308 |
|
309 | | Param | Type | Default | Description |
|
310 | | --- | --- | --- | --- |
|
311 | | [name] | <code>String</code> | | The identifier of a single dependency to be checked |
|
312 | | [dependencies] | <code>Array.<Object></code> | | An explicit set of dependencies to be checked |
|
313 | | [retries] | <code>Integer</code> | <code>1</code> | How many times should a dependency be checked, until it is deemed unhealthy |
|
314 | | [parallel] | <code>Boolean</code> | <code>true</code> | Kick of health checks in parallel or series |
|
315 |
|
316 | **Example**
|
317 | ```js
|
318 | copacetic.check({ name: 'my-dependency' })
|
319 | ```
|
320 | **Example**
|
321 | ```js
|
322 | copacetic.check({ name: 'my-dependency', retries: 5 })
|
323 | .on('healthy', serviceHealth => { ... Do stuff })
|
324 | .on('unhealthy', serviceHealth => { ... Handle degraded state })
|
325 | ```
|
326 | **Example**
|
327 | ```js
|
328 | copacetic.check({ dependencies: [
|
329 | { name: 'my-dep' },
|
330 | { name: 'my-other-dep', retries: 2, maxDelay: '1 second' }
|
331 | ] })
|
332 | .on('health', (servicesHealth) => {
|
333 | // Do something with the result
|
334 | // [{ name: String, health: Boolean, level: HARD/SOFT, lastCheck: Date }]
|
335 | })
|
336 | ```
|
337 | **Example**
|
338 | ```js
|
339 | copacetic.check({ name: 'my-dependency' })
|
340 | .then((health) => { ... Do Stuff })
|
341 | .catch((err) => { ... Handle degraded state })
|
342 | ```
|
343 | <a name="Copacetic+waitFor"></a>
|
344 |
|
345 | ### copacetic.waitFor(opts)
|
346 | Convenience method that waits for a single, or set of dependencies
|
347 | to become healthy. Calling this means copacetic will keep re-checking
|
348 | indefinitely until the dependency(s) become healthy. If you want more
|
349 | control, use .check().
|
350 |
|
351 | **Kind**: instance method of [<code>Copacetic</code>](#Copacetic)
|
352 |
|
353 | | Param | Type | Description |
|
354 | | --- | --- | --- |
|
355 | | opts | <code>Object</code> | options accepted by check() |
|
356 |
|
357 | **Example**
|
358 | ```js
|
359 | // wait indefinitely
|
360 | copacetic.waitFor({ name: 'my-dependency'})
|
361 | .on('healthy', serviceHealth => { ... Do stuff })
|
362 | ```
|
363 | **Example**
|
364 | ```js
|
365 | // give up after 5 tries
|
366 | copacetic.waitFor({ name: 'my-dependency', retries: 5})
|
367 | .on('healthy', serviceHealth => { ... Do stuff })
|
368 | ```
|
369 | <a name="Copacetic+_checkOne"></a>
|
370 |
|
371 | ### copacetic._checkOne(name, maxDelay) ⇒ <code>Promise</code>
|
372 | **Kind**: instance method of [<code>Copacetic</code>](#Copacetic)
|
373 |
|
374 | | Param | Type | Description |
|
375 | | --- | --- | --- |
|
376 | | name | <code>String</code> | The name used to identify a dependency |
|
377 | | maxDelay | <code>Integer</code> | The maximum interval of time to wait when retrying |
|
378 |
|
379 | <a name="Copacetic+_checkMany"></a>
|
380 |
|
381 | ### copacetic._checkMany(dependencies, parallel) ⇒ <code>Promise</code>
|
382 | Checks an array of dependencies in parallel or sequantially
|
383 |
|
384 | **Kind**: instance method of [<code>Copacetic</code>](#Copacetic)
|
385 |
|
386 | | Param | Type |
|
387 | | --- | --- |
|
388 | | dependencies | <code>Array.<Dependency></code> |
|
389 | | parallel | <code>Boolean</code> |
|
390 |
|
391 | <a name="Copacetic+event_healthy"></a>
|
392 |
|
393 | ### "healthy"
|
394 | Health information on a single dependency
|
395 |
|
396 | **Kind**: event emitted by [<code>Copacetic</code>](#Copacetic)
|
397 | <a name="Copacetic+event_unhealthy"></a>
|
398 |
|
399 | ### "unhealthy"
|
400 | Health information on a single dependency
|
401 |
|
402 | **Kind**: event emitted by [<code>Copacetic</code>](#Copacetic)
|
403 | <a name="Copacetic+event_health"></a>
|
404 |
|
405 | ### "health"
|
406 | Health information on a set of dependencies
|
407 |
|
408 | **Kind**: event emitted by [<code>Copacetic</code>](#Copacetic)
|
409 | <a name="HealthReport"></a>
|
410 |
|
411 | ## HealthReport : <code>Object</code>
|
412 | The full health report including isHealthy and dependencies
|
413 |
|
414 | **Kind**: global typedef
|
415 | **Properties**
|
416 |
|
417 | | Name | Type | Description |
|
418 | | --- | --- | --- |
|
419 | | isHealthy | <code>Boolean</code> | The result of [isHealthy](#Copacetic+isHealthy) |
|
420 | | Name | <code>String</code> | |
|
421 | | dependencies | <code>Array.<DependencyHealth></code> | The result of [healthInfo](#Copacetic+healthInfo) |
|
422 |
|