@weave-js/core 0.11.0 → 0.12.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/.eslintrc.js +1 -1
- package/jest.config.js +1 -1
- package/lib/ExtendableError.js +7 -7
- package/lib/broker/context.js +49 -49
- package/lib/broker/defaultOptions.js +9 -9
- package/lib/broker/index.js +161 -165
- package/lib/buildRuntime.js +34 -34
- package/lib/cache/adapters/base.js +119 -0
- package/lib/cache/adapters/inMemory.js +154 -0
- package/lib/cache/adapters/inMemoryLru.js +140 -0
- package/lib/cache/adapters/index.js +10 -0
- package/lib/cache/getCacheKeyByObject.js +31 -0
- package/lib/cache/getPropertyFromDataOrMetadata.js +20 -0
- package/lib/cache/lock.js +30 -24
- package/lib/constants.js +5 -5
- package/lib/errorHandler.js +8 -8
- package/lib/errors.js +35 -35
- package/lib/helper/defineAction.js +2 -2
- package/lib/helper/defineBrokerOptions.js +2 -2
- package/lib/helper/defineService.js +2 -2
- package/lib/index.js +21 -22
- package/lib/logger/base.js +38 -29
- package/lib/logger/format/asHumanReadable.js +15 -15
- package/lib/logger/format/asJson.js +10 -10
- package/lib/logger/format/index.js +3 -3
- package/lib/logger/index.js +24 -24
- package/lib/logger/levels.js +21 -21
- package/lib/logger/tools.js +15 -15
- package/lib/logger/utils/colorize.js +23 -23
- package/lib/logger/utils/format.js +75 -65
- package/lib/metrics/common.js +47 -47
- package/lib/metrics/constants.js +44 -44
- package/lib/metrics/exporter/base.js +8 -8
- package/lib/metrics/exporter/event.js +20 -20
- package/lib/metrics/exporter/index.js +15 -15
- package/lib/metrics/index.js +2 -2
- package/lib/metrics/types/base.js +20 -20
- package/lib/metrics/types/counter.js +6 -6
- package/lib/metrics/types/gauge.js +24 -24
- package/lib/metrics/types/histogram.js +26 -26
- package/lib/metrics/types/index.js +6 -6
- package/lib/metrics/types/info.js +17 -17
- package/lib/middlewares/action-hooks/index.js +38 -38
- package/lib/middlewares/bulkhead/index.js +34 -34
- package/lib/middlewares/cache/index.js +63 -37
- package/lib/middlewares/circuit-breaker/index.js +62 -62
- package/lib/middlewares/context-tracker/index.js +39 -39
- package/lib/middlewares/error-handler/index.js +47 -15
- package/lib/middlewares/index.js +2 -2
- package/lib/middlewares/metrics/getMiddlewareWrapper.js +17 -17
- package/lib/middlewares/metrics/index.js +29 -29
- package/lib/middlewares/retry/index.js +15 -15
- package/lib/middlewares/timeout/index.js +16 -16
- package/lib/middlewares/tracing/index.js +37 -37
- package/lib/middlewares/tracing/tags.js +6 -6
- package/lib/middlewares/validator/index.js +31 -31
- package/lib/registry/actionEndpoint.js +8 -8
- package/lib/registry/collections/actionCollection.js +39 -35
- package/lib/registry/collections/endpointCollection.js +63 -63
- package/lib/registry/collections/eventCollection.js +62 -62
- package/lib/registry/collections/nodeCollection.js +45 -45
- package/lib/registry/collections/serviceCollection.js +61 -55
- package/lib/registry/eventEndpoint.js +14 -14
- package/lib/registry/load-balancer/base.js +3 -3
- package/lib/registry/load-balancer/index.js +7 -7
- package/lib/registry/node.js +27 -27
- package/lib/registry/registry.js +145 -148
- package/lib/registry/service/parseAction.js +16 -16
- package/lib/registry/service/parseEvent.js +18 -18
- package/lib/registry/service/reduceMixins.js +10 -10
- package/lib/registry/service/service.js +72 -72
- package/lib/registry/serviceItem.js +21 -21
- package/lib/runtime/initActionInvoker.js +21 -21
- package/lib/runtime/initCache.js +14 -5
- package/lib/runtime/initContextFactory.js +22 -22
- package/lib/runtime/initEventbus.js +49 -49
- package/lib/runtime/initLogger.js +11 -11
- package/lib/runtime/initMetrics.js +54 -54
- package/lib/runtime/initMiddlewareManager.js +21 -21
- package/lib/runtime/initRegistry.js +6 -6
- package/lib/runtime/initServiceManager.js +85 -68
- package/lib/runtime/initTracing.js +23 -23
- package/lib/runtime/initTransport.js +5 -5
- package/lib/runtime/initUuidFactory.js +4 -4
- package/lib/runtime/initValidator.js +5 -5
- package/lib/tracing/collectors/base.js +22 -22
- package/lib/tracing/collectors/event.js +33 -33
- package/lib/tracing/collectors/index.js +15 -15
- package/lib/tracing/span.js +26 -26
- package/lib/tracing/time.js +8 -8
- package/lib/transport/InboundTransformStream.js +26 -26
- package/lib/transport/adapters/adapteBase.js +30 -30
- package/lib/transport/adapters/adapters.js +4 -4
- package/lib/transport/adapters/dummy/index.js +18 -18
- package/lib/transport/adapters/fromURI.js +13 -13
- package/lib/transport/adapters/getAdapterByName.js +5 -5
- package/lib/transport/adapters/index.js +12 -12
- package/lib/transport/adapters/tcp/discovery/codec.js +4 -4
- package/lib/transport/adapters/tcp/discovery/index.js +62 -62
- package/lib/transport/adapters/tcp/index.js +169 -171
- package/lib/transport/adapters/tcp/tcp-messagetypes.js +7 -7
- package/lib/transport/adapters/tcp/tcpReader.js +39 -39
- package/lib/transport/adapters/tcp/tcpWriteStream.js +26 -26
- package/lib/transport/adapters/tcp/tcpWriter.js +57 -57
- package/lib/transport/adapters/tcp/utils.js +12 -12
- package/lib/transport/createMessage.js +4 -4
- package/lib/transport/createTransport.js +254 -254
- package/lib/transport/errorPayloadFactory.js +14 -17
- package/lib/transport/messageHandlers.js +200 -200
- package/lib/transport/messageTypes.js +19 -19
- package/lib/types.js +49 -25
- package/lib/utils/index.js +2 -2
- package/lib/utils/options.js +44 -44
- package/lib/utils/restoreError.js +4 -4
- package/package.json +4 -4
- package/lib/cache/base.js +0 -147
- package/lib/cache/inMemory.js +0 -140
- package/lib/cache/index.js +0 -48
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Author: Kevin Ries (kevin@
|
|
2
|
+
* Author: Kevin Ries (kevin.ries@fachwerk.io)
|
|
3
3
|
* -----
|
|
4
4
|
* Copyright 2021 Fachwerk
|
|
5
5
|
*/
|
|
6
|
-
const { Constants } = require('../../metrics')
|
|
7
|
-
const { WeaveQueueSizeExceededError } = require('../../errors')
|
|
6
|
+
const { Constants } = require('../../metrics');
|
|
7
|
+
const { WeaveQueueSizeExceededError } = require('../../errors');
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* @typedef {import('../../types').Runtime} Runtime
|
|
@@ -18,47 +18,47 @@ const { WeaveQueueSizeExceededError } = require('../../errors')
|
|
|
18
18
|
*/
|
|
19
19
|
module.exports = (runtime) => {
|
|
20
20
|
const wrapBulkheadMiddleware = function (handler, action) {
|
|
21
|
-
const bulkheadOptions = runtime.options.bulkhead
|
|
21
|
+
const bulkheadOptions = runtime.options.bulkhead;
|
|
22
22
|
|
|
23
23
|
if (bulkheadOptions.enabled) {
|
|
24
|
-
const queue = []
|
|
25
|
-
let currentlyInFlight = 0
|
|
24
|
+
const queue = [];
|
|
25
|
+
let currentlyInFlight = 0;
|
|
26
26
|
|
|
27
27
|
const callNext = () => {
|
|
28
|
-
if (queue.length === 0) return
|
|
29
|
-
if (currentlyInFlight >= bulkheadOptions.concurrentCalls) return
|
|
28
|
+
if (queue.length === 0) return;
|
|
29
|
+
if (currentlyInFlight >= bulkheadOptions.concurrentCalls) return;
|
|
30
30
|
|
|
31
|
-
const item = queue.shift()
|
|
31
|
+
const item = queue.shift();
|
|
32
32
|
|
|
33
|
-
currentlyInFlight
|
|
33
|
+
currentlyInFlight++;
|
|
34
34
|
handler(item.context)
|
|
35
35
|
.then(result => {
|
|
36
|
-
currentlyInFlight
|
|
37
|
-
item.resolve(result)
|
|
38
|
-
callNext()
|
|
36
|
+
currentlyInFlight--;
|
|
37
|
+
item.resolve(result);
|
|
38
|
+
callNext();
|
|
39
39
|
})
|
|
40
40
|
.catch(error => {
|
|
41
|
-
currentlyInFlight
|
|
42
|
-
callNext()
|
|
43
|
-
return item.reject(error)
|
|
44
|
-
})
|
|
45
|
-
}
|
|
41
|
+
currentlyInFlight--;
|
|
42
|
+
callNext();
|
|
43
|
+
return item.reject(error);
|
|
44
|
+
});
|
|
45
|
+
};
|
|
46
46
|
|
|
47
47
|
return function bulkheadMiddlware (context, serviceInjections) {
|
|
48
48
|
// Execute action immediately
|
|
49
49
|
if (currentlyInFlight < bulkheadOptions.concurrentCalls) {
|
|
50
|
-
currentlyInFlight
|
|
50
|
+
currentlyInFlight++;
|
|
51
51
|
return handler(context, serviceInjections)
|
|
52
52
|
.then(result => {
|
|
53
|
-
currentlyInFlight
|
|
54
|
-
callNext()
|
|
55
|
-
return result
|
|
53
|
+
currentlyInFlight--;
|
|
54
|
+
callNext();
|
|
55
|
+
return result;
|
|
56
56
|
})
|
|
57
57
|
.catch(error => {
|
|
58
|
-
currentlyInFlight
|
|
59
|
-
callNext()
|
|
60
|
-
return Promise.reject(error)
|
|
61
|
-
})
|
|
58
|
+
currentlyInFlight--;
|
|
59
|
+
callNext();
|
|
60
|
+
return Promise.reject(error);
|
|
61
|
+
});
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
// Reject the action if the max queue size is reached.
|
|
@@ -67,23 +67,23 @@ module.exports = (runtime) => {
|
|
|
67
67
|
action: action.name,
|
|
68
68
|
limit: bulkheadOptions.maxQueueSize,
|
|
69
69
|
size: queue.length
|
|
70
|
-
}))
|
|
70
|
+
}));
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
// Queue the request
|
|
74
|
-
return new Promise((resolve, reject) => queue.push({ resolve, reject, context }))
|
|
75
|
-
}
|
|
74
|
+
return new Promise((resolve, reject) => queue.push({ resolve, reject, context }));
|
|
75
|
+
};
|
|
76
76
|
}
|
|
77
|
-
return handler
|
|
78
|
-
}
|
|
77
|
+
return handler;
|
|
78
|
+
};
|
|
79
79
|
|
|
80
80
|
return {
|
|
81
81
|
created () {
|
|
82
82
|
if (runtime.options.metrics.enabled) {
|
|
83
83
|
// todo: add bulkhead metrics
|
|
84
|
-
runtime.metrics.register({ type: 'gauge', name: Constants.BULKHEAD_REQUESTS_IN_FLIGHT, description: 'Number of in flight requests.' })
|
|
84
|
+
runtime.metrics.register({ type: 'gauge', name: Constants.BULKHEAD_REQUESTS_IN_FLIGHT, description: 'Number of in flight requests.' });
|
|
85
85
|
}
|
|
86
86
|
},
|
|
87
87
|
localAction: wrapBulkheadMiddleware
|
|
88
|
-
}
|
|
89
|
-
}
|
|
88
|
+
};
|
|
89
|
+
};
|
|
@@ -1,80 +1,106 @@
|
|
|
1
|
-
const {
|
|
1
|
+
const { isString, isFunction } = require('@weave-js/utils');
|
|
2
2
|
|
|
3
3
|
module.exports = (runtime) => {
|
|
4
4
|
return {
|
|
5
5
|
localAction: (handler, action) => {
|
|
6
|
-
const cacheOptions =
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
const cacheOptions = runtime.options.cache;
|
|
7
|
+
const cacheActionOptions = {
|
|
8
|
+
enabled: !!action.cache
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
if (isString(action.cache)) {
|
|
12
|
+
cacheActionOptions.keys = action.cache.split(' ');
|
|
13
|
+
} else if (action.cache && Array.isArray(action.cache.keys)) {
|
|
14
|
+
cacheActionOptions.keys = action.cache.keys;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (cacheActionOptions.enabled) {
|
|
18
|
+
const cache = runtime.cache;
|
|
19
|
+
const isEnabledFunction = isFunction(action.cache.condition);
|
|
20
|
+
|
|
11
21
|
return function cacheMiddleware (context, serviceInjections) {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
22
|
+
// handle enabled function
|
|
23
|
+
if (isEnabledFunction) {
|
|
24
|
+
if (!action.cache.enabled.call(null, context)) {
|
|
25
|
+
// Enabled function returns "false". Cache is disabled.
|
|
26
|
+
return handler(context, serviceInjections);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Generate cache hash
|
|
31
|
+
const cacheHashKey = cache.getCachingKey(
|
|
32
|
+
action.name,
|
|
33
|
+
context.data,
|
|
34
|
+
context.meta,
|
|
35
|
+
cacheActionOptions.keys
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
context.isCachedResult = false;
|
|
15
39
|
|
|
40
|
+
// Disable caching by meta property.
|
|
16
41
|
if (context.meta.$noCache === true) {
|
|
17
|
-
return handler(context, serviceInjections)
|
|
42
|
+
return handler(context, serviceInjections);
|
|
18
43
|
}
|
|
19
44
|
|
|
45
|
+
// The cache adapter is not connected yet. In this case, we call the handler regular
|
|
20
46
|
if (cache.isConnected === false) {
|
|
21
|
-
cache.log('Cache adapter is not connected yet. Call handler...')
|
|
22
|
-
return handler(context, serviceInjections)
|
|
47
|
+
cache.log('Cache adapter is not connected yet. Call handler...');
|
|
48
|
+
return handler(context, serviceInjections);
|
|
23
49
|
}
|
|
24
50
|
|
|
25
51
|
if (cacheOptions.lock.enabled) {
|
|
26
|
-
let
|
|
52
|
+
let cachePromise;
|
|
27
53
|
if (cacheOptions.lock.staleTime && cache.getWithTTl) {
|
|
28
54
|
|
|
29
55
|
} else {
|
|
30
|
-
|
|
56
|
+
cachePromise = runtime.cache.get(cacheHashKey);
|
|
31
57
|
}
|
|
32
58
|
|
|
33
|
-
return
|
|
59
|
+
return cachePromise.then((cachedResult) => {
|
|
34
60
|
if (cachedResult !== null) {
|
|
35
61
|
// Found a cached value. Skip calling handler and return our value
|
|
36
|
-
context.isCachedResult = true
|
|
37
|
-
return cachedResult
|
|
62
|
+
context.isCachedResult = true;
|
|
63
|
+
return cachedResult;
|
|
38
64
|
}
|
|
39
65
|
|
|
40
66
|
return cache.lock(cacheHashKey).then((release) => {
|
|
41
67
|
return cache.get(cacheHashKey).then(cachedResult => {
|
|
42
68
|
if (cachedResult !== null) {
|
|
43
69
|
// Found a cached value. Skip calling handler and return our value
|
|
44
|
-
context.isCachedResult = true
|
|
70
|
+
context.isCachedResult = true;
|
|
45
71
|
return release().then(() => {
|
|
46
|
-
return cachedResult
|
|
47
|
-
})
|
|
72
|
+
return cachedResult;
|
|
73
|
+
});
|
|
48
74
|
}
|
|
49
75
|
|
|
50
76
|
return handler(context).then((result) => {
|
|
51
77
|
// Cache the value
|
|
52
78
|
cache.set(cacheHashKey, result, action.cache.ttl).then(() => {
|
|
53
79
|
// release the lock
|
|
54
|
-
release()
|
|
55
|
-
})
|
|
56
|
-
return result
|
|
57
|
-
})
|
|
58
|
-
})
|
|
59
|
-
})
|
|
60
|
-
})
|
|
80
|
+
release();
|
|
81
|
+
});
|
|
82
|
+
return result;
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
});
|
|
61
87
|
}
|
|
62
88
|
|
|
63
89
|
// Not using cache lock
|
|
64
90
|
return runtime.cache.get(cacheHashKey).then((cachedResult) => {
|
|
65
91
|
if (cachedResult !== null) {
|
|
66
|
-
context.isCachedResult = true
|
|
67
|
-
return cachedResult
|
|
92
|
+
context.isCachedResult = true;
|
|
93
|
+
return cachedResult;
|
|
68
94
|
}
|
|
69
95
|
|
|
70
96
|
return handler(context, serviceInjections).then((result) => {
|
|
71
|
-
runtime.cache.set(cacheHashKey, result, action.cache.ttl)
|
|
72
|
-
return result
|
|
73
|
-
})
|
|
74
|
-
})
|
|
75
|
-
}
|
|
97
|
+
runtime.cache.set(cacheHashKey, result, action.cache.ttl);
|
|
98
|
+
return result;
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
};
|
|
76
102
|
}
|
|
77
|
-
return handler
|
|
103
|
+
return handler;
|
|
78
104
|
}
|
|
79
|
-
}
|
|
80
|
-
}
|
|
105
|
+
};
|
|
106
|
+
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Author: Kevin Ries (kevin@
|
|
2
|
+
* Author: Kevin Ries (kevin.ries@fachwerk.io)
|
|
3
3
|
* -----
|
|
4
4
|
* Copyright 2021 Fachwerk
|
|
5
5
|
*/
|
|
@@ -8,32 +8,32 @@ const {
|
|
|
8
8
|
CIRCUIT_HALF_OPENED,
|
|
9
9
|
CIRCUIT_HALF_OPEN_WAITING,
|
|
10
10
|
CIRCUIT_OPENED
|
|
11
|
-
} = require('../../constants').circuitBreakerStates
|
|
11
|
+
} = require('../../constants').circuitBreakerStates;
|
|
12
12
|
|
|
13
13
|
module.exports = (runtime) => {
|
|
14
|
-
const storage = new Map()
|
|
15
|
-
let log = null
|
|
16
|
-
let circuitBreakerTimer = null
|
|
14
|
+
const storage = new Map();
|
|
15
|
+
let log = null;
|
|
16
|
+
let circuitBreakerTimer = null;
|
|
17
17
|
|
|
18
18
|
function createWindowTimer (windowTime) {
|
|
19
|
-
circuitBreakerTimer = setInterval(() => clearEndpointStore(), windowTime)
|
|
20
|
-
circuitBreakerTimer.unref()
|
|
19
|
+
circuitBreakerTimer = setInterval(() => clearEndpointStore(), windowTime);
|
|
20
|
+
circuitBreakerTimer.unref();
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
function clearEndpointStore () {
|
|
24
24
|
storage.forEach((item) => {
|
|
25
25
|
if (item.callCounter === 0) {
|
|
26
|
-
storage.delete(item.name)
|
|
27
|
-
return
|
|
26
|
+
storage.delete(item.name);
|
|
27
|
+
return;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
item.callCounter = 0
|
|
31
|
-
item.failureCouter = 0
|
|
32
|
-
})
|
|
30
|
+
item.callCounter = 0;
|
|
31
|
+
item.failureCouter = 0;
|
|
32
|
+
});
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
function getEndpointState (endpoint, options) {
|
|
36
|
-
let item = storage.get(endpoint.name)
|
|
36
|
+
let item = storage.get(endpoint.name);
|
|
37
37
|
if (!item) {
|
|
38
38
|
item = {
|
|
39
39
|
endpoint,
|
|
@@ -42,127 +42,127 @@ module.exports = (runtime) => {
|
|
|
42
42
|
failureCouter: 0,
|
|
43
43
|
state: CIRCUIT_CLOSED,
|
|
44
44
|
circuitBreakerTimer: null
|
|
45
|
-
}
|
|
46
|
-
storage.set(endpoint.name, item)
|
|
45
|
+
};
|
|
46
|
+
storage.set(endpoint.name, item);
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
return item
|
|
49
|
+
return item;
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
function onSuccess (item, options) {
|
|
53
|
-
item.callCounter
|
|
53
|
+
item.callCounter++;
|
|
54
54
|
|
|
55
55
|
if (item.state === CIRCUIT_HALF_OPENED) {
|
|
56
|
-
closeCircuitBreaker(item)
|
|
56
|
+
closeCircuitBreaker(item);
|
|
57
57
|
} else {
|
|
58
|
-
checkThreshold(item, options)
|
|
58
|
+
checkThreshold(item, options);
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
function onFailure (item, options) {
|
|
63
|
-
item.callCounter
|
|
64
|
-
item.failureCouter
|
|
63
|
+
item.callCounter++;
|
|
64
|
+
item.failureCouter++;
|
|
65
65
|
|
|
66
|
-
checkThreshold(item, options)
|
|
66
|
+
checkThreshold(item, options);
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
function checkThreshold (item, options) {
|
|
70
70
|
if (item.failureCouter >= options.maxFailures) {
|
|
71
|
-
openCircuitBreaker(item)
|
|
71
|
+
openCircuitBreaker(item);
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
function openCircuitBreaker (item) {
|
|
76
|
-
item.state = CIRCUIT_OPENED
|
|
77
|
-
item.endpoint.state = false
|
|
78
|
-
item.circuitBreakerTimer = setTimeout(() => halfOpenCircuitBreaker(item), item.options.halfOpenTimeout)
|
|
79
|
-
item.circuitBreakerTimer.unref()
|
|
80
|
-
log.debug(`Circuit breaker has been opened for endpoint '${item.endpoint.name}'`)
|
|
76
|
+
item.state = CIRCUIT_OPENED;
|
|
77
|
+
item.endpoint.state = false;
|
|
78
|
+
item.circuitBreakerTimer = setTimeout(() => halfOpenCircuitBreaker(item), item.options.halfOpenTimeout);
|
|
79
|
+
item.circuitBreakerTimer.unref();
|
|
80
|
+
log.debug(`Circuit breaker has been opened for endpoint '${item.endpoint.name}'`);
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
function halfOpenCircuitBreaker (item) {
|
|
84
|
-
item.state = CIRCUIT_HALF_OPENED
|
|
85
|
-
item.endpoint.state = true
|
|
84
|
+
item.state = CIRCUIT_HALF_OPENED;
|
|
85
|
+
item.endpoint.state = true;
|
|
86
86
|
|
|
87
|
-
log.debug(`Circuit breaker has been half opened for endpoint '${item.endpoint.name}'`)
|
|
87
|
+
log.debug(`Circuit breaker has been half opened for endpoint '${item.endpoint.name}'`);
|
|
88
88
|
|
|
89
89
|
if (item.circuitBreakerTimer) {
|
|
90
|
-
clearTimeout(item.circuitBreakerTimer)
|
|
91
|
-
item.circuitBreakerTimer = null
|
|
90
|
+
clearTimeout(item.circuitBreakerTimer);
|
|
91
|
+
item.circuitBreakerTimer = null;
|
|
92
92
|
}
|
|
93
93
|
}
|
|
94
94
|
|
|
95
95
|
function handleHalfOpen (item) {
|
|
96
|
-
item.state = CIRCUIT_HALF_OPEN_WAITING
|
|
97
|
-
item.endpoint.state = false
|
|
98
|
-
item.circuitBreakerTimer = setTimeout(() => halfOpenCircuitBreaker(item), item.options.halfOpenTimeout)
|
|
99
|
-
item.circuitBreakerTimer.unref()
|
|
96
|
+
item.state = CIRCUIT_HALF_OPEN_WAITING;
|
|
97
|
+
item.endpoint.state = false;
|
|
98
|
+
item.circuitBreakerTimer = setTimeout(() => halfOpenCircuitBreaker(item), item.options.halfOpenTimeout);
|
|
99
|
+
item.circuitBreakerTimer.unref();
|
|
100
100
|
}
|
|
101
101
|
|
|
102
102
|
function closeCircuitBreaker (item) {
|
|
103
|
-
item.failureCouter = 0
|
|
104
|
-
item.callCounter = 0
|
|
105
|
-
item.state = CIRCUIT_CLOSED
|
|
106
|
-
item.endpoint.state = true
|
|
103
|
+
item.failureCouter = 0;
|
|
104
|
+
item.callCounter = 0;
|
|
105
|
+
item.state = CIRCUIT_CLOSED;
|
|
106
|
+
item.endpoint.state = true;
|
|
107
107
|
|
|
108
108
|
if (item.circuitBreakerTimer) {
|
|
109
|
-
clearTimeout(item.circuitBreakerTimer)
|
|
110
|
-
item.circuitBreakerTimer = null
|
|
109
|
+
clearTimeout(item.circuitBreakerTimer);
|
|
110
|
+
item.circuitBreakerTimer = null;
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
-
log.debug(`Circuit breaker has been closed for endpoint '${item.endpoint.name}'`)
|
|
113
|
+
log.debug(`Circuit breaker has been closed for endpoint '${item.endpoint.name}'`);
|
|
114
114
|
}
|
|
115
115
|
|
|
116
116
|
function wrapCircuitBreakerMiddleware (handler, action) {
|
|
117
|
-
const options = Object.assign({}, runtime.options.circuitBreaker, action.circuitBreaker || {})
|
|
117
|
+
const options = Object.assign({}, runtime.options.circuitBreaker, action.circuitBreaker || {});
|
|
118
118
|
|
|
119
119
|
if (options.enabled) {
|
|
120
120
|
return function curcuitBreakerMiddleware (context, serviceInjections) {
|
|
121
|
-
const endpoint = context.endpoint
|
|
122
|
-
const item = getEndpointState(endpoint, options)
|
|
121
|
+
const endpoint = context.endpoint;
|
|
122
|
+
const item = getEndpointState(endpoint, options);
|
|
123
123
|
|
|
124
124
|
// handle half open states
|
|
125
125
|
if (item.state === CIRCUIT_HALF_OPENED) {
|
|
126
|
-
handleHalfOpen(item, context)
|
|
126
|
+
handleHalfOpen(item, context);
|
|
127
127
|
}
|
|
128
128
|
|
|
129
129
|
return handler(context, serviceInjections)
|
|
130
130
|
.then(result => {
|
|
131
|
-
const item = getEndpointState(endpoint, options)
|
|
132
|
-
onSuccess(item, options)
|
|
131
|
+
const item = getEndpointState(endpoint, options);
|
|
132
|
+
onSuccess(item, options);
|
|
133
133
|
|
|
134
|
-
return result
|
|
134
|
+
return result;
|
|
135
135
|
})
|
|
136
136
|
.catch(error => {
|
|
137
137
|
if (item && (!error.nodeId || error.nodeId === context.nodeId)) {
|
|
138
|
-
onFailure(item, options)
|
|
138
|
+
onFailure(item, options);
|
|
139
139
|
}
|
|
140
140
|
|
|
141
|
-
return Promise.reject(error)
|
|
142
|
-
})
|
|
143
|
-
}
|
|
141
|
+
return Promise.reject(error);
|
|
142
|
+
});
|
|
143
|
+
};
|
|
144
144
|
}
|
|
145
|
-
return handler
|
|
145
|
+
return handler;
|
|
146
146
|
}
|
|
147
147
|
|
|
148
148
|
return {
|
|
149
149
|
created () {
|
|
150
|
-
log = runtime.createLogger('circuit-breaker')
|
|
150
|
+
log = runtime.createLogger('circuit-breaker');
|
|
151
151
|
|
|
152
152
|
if (runtime.options.metrics.enabled) {
|
|
153
153
|
// todo: add circuit breaker metrics
|
|
154
154
|
}
|
|
155
155
|
},
|
|
156
156
|
started () {
|
|
157
|
-
const { enabled, windowTime } = this.options.circuitBreaker
|
|
157
|
+
const { enabled, windowTime } = this.options.circuitBreaker;
|
|
158
158
|
if (enabled) {
|
|
159
|
-
createWindowTimer(windowTime)
|
|
159
|
+
createWindowTimer(windowTime);
|
|
160
160
|
}
|
|
161
161
|
},
|
|
162
162
|
localAction: wrapCircuitBreakerMiddleware,
|
|
163
163
|
remoteAction: wrapCircuitBreakerMiddleware,
|
|
164
164
|
brokerStopped () {
|
|
165
|
-
clearInterval(circuitBreakerTimer)
|
|
165
|
+
clearInterval(circuitBreakerTimer);
|
|
166
166
|
}
|
|
167
|
-
}
|
|
168
|
-
}
|
|
167
|
+
};
|
|
168
|
+
};
|
|
@@ -1,107 +1,107 @@
|
|
|
1
|
-
const { WeaveGracefulStopTimeoutError } = require('../../errors')
|
|
1
|
+
const { WeaveGracefulStopTimeoutError } = require('../../errors');
|
|
2
2
|
|
|
3
3
|
module.exports = (runtime) => {
|
|
4
4
|
function addContext (context) {
|
|
5
5
|
if (context.service) {
|
|
6
6
|
// local actions
|
|
7
|
-
context.service._trackedContexts.push(context)
|
|
7
|
+
context.service._trackedContexts.push(context);
|
|
8
8
|
} else {
|
|
9
9
|
// remote actions
|
|
10
|
-
context.service._trackedContexts.push(context)
|
|
10
|
+
context.service._trackedContexts.push(context);
|
|
11
11
|
}
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
function removeContext (context) {
|
|
15
15
|
if (context.service) {
|
|
16
16
|
// local actions
|
|
17
|
-
const index = context.service._trackedContexts.indexOf(context)
|
|
17
|
+
const index = context.service._trackedContexts.indexOf(context);
|
|
18
18
|
if (index !== -1) {
|
|
19
|
-
context.service._trackedContexts.splice(index, 1)
|
|
19
|
+
context.service._trackedContexts.splice(index, 1);
|
|
20
20
|
}
|
|
21
21
|
} else {
|
|
22
|
-
const index = context.service._trackedContexts.indexOf(context)
|
|
22
|
+
const index = context.service._trackedContexts.indexOf(context);
|
|
23
23
|
if (index !== -1) {
|
|
24
|
-
context.service._trackedContexts.splice(index, 1)
|
|
24
|
+
context.service._trackedContexts.splice(index, 1);
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
function wrapContextTrackerMiddleware (actionHandler) {
|
|
30
30
|
return function ContextTrackerMiddleware (context, serviceInjections) {
|
|
31
|
-
const isTracked = context.options.track === true ? context.options.track : runtime.options.contextTracking.enabled
|
|
31
|
+
const isTracked = context.options.track === true ? context.options.track : runtime.options.contextTracking.enabled;
|
|
32
32
|
|
|
33
33
|
if (!isTracked) {
|
|
34
|
-
return actionHandler(context, serviceInjections)
|
|
34
|
+
return actionHandler(context, serviceInjections);
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
addContext(context)
|
|
37
|
+
addContext(context);
|
|
38
38
|
|
|
39
39
|
return actionHandler(context, serviceInjections)
|
|
40
40
|
.then(result => {
|
|
41
|
-
removeContext(context)
|
|
42
|
-
return result
|
|
41
|
+
removeContext(context);
|
|
42
|
+
return result;
|
|
43
43
|
})
|
|
44
44
|
.catch(error => {
|
|
45
|
-
removeContext(context)
|
|
46
|
-
throw error
|
|
47
|
-
})
|
|
48
|
-
}
|
|
45
|
+
removeContext(context);
|
|
46
|
+
throw error;
|
|
47
|
+
});
|
|
48
|
+
};
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
const waitingForActiveContexts = (contextList, log, shutdownTimeout, service) => {
|
|
52
52
|
return new Promise((resolve) => {
|
|
53
53
|
if (contextList.length === 0) {
|
|
54
|
-
resolve()
|
|
54
|
+
resolve();
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
let isTimedOut = false
|
|
57
|
+
let isTimedOut = false;
|
|
58
58
|
const timeout = setTimeout(() => {
|
|
59
|
-
isTimedOut = true
|
|
60
|
-
log.error(new WeaveGracefulStopTimeoutError(service))
|
|
61
|
-
contextList = []
|
|
62
|
-
resolve()
|
|
63
|
-
}, shutdownTimeout)
|
|
59
|
+
isTimedOut = true;
|
|
60
|
+
log.error(new WeaveGracefulStopTimeoutError(service));
|
|
61
|
+
contextList = [];
|
|
62
|
+
resolve();
|
|
63
|
+
}, shutdownTimeout);
|
|
64
64
|
|
|
65
|
-
let isFirstCheck = true
|
|
65
|
+
let isFirstCheck = true;
|
|
66
66
|
const checkContexts = () => {
|
|
67
67
|
if (contextList.length === 0) {
|
|
68
|
-
clearTimeout(timeout)
|
|
69
|
-
resolve()
|
|
68
|
+
clearTimeout(timeout);
|
|
69
|
+
resolve();
|
|
70
70
|
} else {
|
|
71
71
|
if (isFirstCheck) {
|
|
72
|
-
log.info(`Waiting for ${contextList.length} open Contexts...`)
|
|
73
|
-
isFirstCheck = false
|
|
72
|
+
log.info(`Waiting for ${contextList.length} open Contexts...`);
|
|
73
|
+
isFirstCheck = false;
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
if (!isTimedOut) {
|
|
77
|
-
setTimeout(checkContexts, 100)
|
|
77
|
+
setTimeout(checkContexts, 100);
|
|
78
78
|
}
|
|
79
79
|
}
|
|
80
|
-
}
|
|
81
|
-
setImmediate(checkContexts)
|
|
82
|
-
})
|
|
83
|
-
}
|
|
80
|
+
};
|
|
81
|
+
setImmediate(checkContexts);
|
|
82
|
+
});
|
|
83
|
+
};
|
|
84
84
|
|
|
85
85
|
return {
|
|
86
86
|
created () {
|
|
87
87
|
// init context-store
|
|
88
|
-
runtime.state.trackedContexts = []
|
|
88
|
+
runtime.state.trackedContexts = [];
|
|
89
89
|
},
|
|
90
90
|
serviceStarting (service) {
|
|
91
|
-
service._trackedContexts = []
|
|
91
|
+
service._trackedContexts = [];
|
|
92
92
|
},
|
|
93
93
|
|
|
94
94
|
// Before a local service stopping
|
|
95
95
|
serviceStopping (service) {
|
|
96
|
-
return waitingForActiveContexts(service._trackedContexts, service.log, service.settings.$shutdownTimeout || service.broker.options.contextTracking.shutdownTimeout, service)
|
|
96
|
+
return waitingForActiveContexts(service._trackedContexts, service.log, service.settings.$shutdownTimeout || service.broker.options.contextTracking.shutdownTimeout, service);
|
|
97
97
|
},
|
|
98
98
|
|
|
99
99
|
// Before broker stopping
|
|
100
100
|
stopping () {
|
|
101
|
-
return waitingForActiveContexts(runtime.state.trackedContexts, runtime.log, runtime.options.contextTracking.shutdownTimeout)
|
|
101
|
+
return waitingForActiveContexts(runtime.state.trackedContexts, runtime.log, runtime.options.contextTracking.shutdownTimeout);
|
|
102
102
|
},
|
|
103
103
|
localAction: wrapContextTrackerMiddleware,
|
|
104
104
|
remoteAction: wrapContextTrackerMiddleware,
|
|
105
105
|
localEvent: wrapContextTrackerMiddleware
|
|
106
|
-
}
|
|
107
|
-
}
|
|
106
|
+
};
|
|
107
|
+
};
|