@weave-js/core 0.10.0 → 0.12.0

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.
Files changed (132) hide show
  1. package/.eslintrc.js +1 -1
  2. package/jest.config.js +1 -1
  3. package/lib/ExtendableError.js +33 -0
  4. package/lib/broker/context.js +58 -46
  5. package/lib/broker/{default-options.js → defaultOptions.js} +31 -13
  6. package/lib/broker/index.js +273 -251
  7. package/lib/buildRuntime.js +70 -0
  8. package/lib/cache/adapters/base.js +119 -0
  9. package/lib/cache/adapters/inMemory.js +154 -0
  10. package/lib/cache/adapters/inMemoryLru.js +140 -0
  11. package/lib/cache/adapters/index.js +10 -0
  12. package/lib/cache/getCacheKeyByObject.js +31 -0
  13. package/lib/cache/getPropertyFromDataOrMetadata.js +20 -0
  14. package/lib/cache/lock.js +34 -11
  15. package/lib/constants.js +11 -8
  16. package/lib/{error-handler.js → errorHandler.js} +8 -8
  17. package/lib/errors.js +46 -39
  18. package/lib/helper/{define-action.js → defineAction.js} +5 -3
  19. package/lib/helper/{define-broker-options.js → defineBrokerOptions.js} +4 -2
  20. package/lib/helper/{define-service.js → defineService.js} +6 -3
  21. package/lib/index.js +25 -22
  22. package/lib/logger/base.js +38 -29
  23. package/lib/logger/format/asHumanReadable.js +15 -14
  24. package/lib/logger/format/asJson.js +10 -10
  25. package/lib/logger/format/index.js +3 -3
  26. package/lib/logger/index.js +28 -25
  27. package/lib/logger/levels.js +23 -22
  28. package/lib/logger/tools.js +17 -13
  29. package/lib/logger/utils/colorize.js +23 -23
  30. package/lib/logger/utils/format.js +89 -65
  31. package/lib/metrics/common.js +47 -47
  32. package/lib/metrics/constants.js +44 -44
  33. package/lib/metrics/exporter/base.js +8 -8
  34. package/lib/metrics/exporter/event.js +20 -20
  35. package/lib/metrics/exporter/index.js +15 -15
  36. package/lib/metrics/index.js +2 -2
  37. package/lib/metrics/types/base.js +20 -20
  38. package/lib/metrics/types/counter.js +6 -6
  39. package/lib/metrics/types/gauge.js +24 -24
  40. package/lib/metrics/types/histogram.js +26 -26
  41. package/lib/metrics/types/index.js +6 -6
  42. package/lib/metrics/types/info.js +17 -17
  43. package/lib/middlewares/action-hooks/index.js +82 -34
  44. package/lib/middlewares/bulkhead/index.js +34 -33
  45. package/lib/middlewares/cache/index.js +106 -0
  46. package/lib/middlewares/circuit-breaker/index.js +85 -60
  47. package/lib/middlewares/context-tracker/index.js +39 -39
  48. package/lib/middlewares/error-handler/index.js +14 -14
  49. package/lib/middlewares/index.js +3 -2
  50. package/lib/middlewares/metrics/getMiddlewareWrapper.js +17 -17
  51. package/lib/middlewares/metrics/index.js +29 -29
  52. package/lib/middlewares/retry/index.js +15 -15
  53. package/lib/middlewares/timeout/index.js +18 -18
  54. package/lib/middlewares/tracing/index.js +50 -37
  55. package/lib/middlewares/tracing/tags.js +43 -0
  56. package/lib/middlewares/validator/index.js +32 -32
  57. package/lib/registry/{action-endpoint.js → actionEndpoint.js} +8 -8
  58. package/lib/registry/collections/{action-collection.js → actionCollection.js} +39 -35
  59. package/lib/registry/collections/{endpoint-collection.js → endpointCollection.js} +64 -65
  60. package/lib/registry/collections/{event-collection.js → eventCollection.js} +65 -69
  61. package/lib/registry/collections/{node-collection.js → nodeCollection.js} +45 -45
  62. package/lib/registry/collections/{service-collection.js → serviceCollection.js} +61 -55
  63. package/lib/registry/eventEndpoint.js +26 -0
  64. package/lib/registry/load-balancer/base.js +3 -3
  65. package/lib/registry/load-balancer/index.js +7 -7
  66. package/lib/registry/node.js +27 -27
  67. package/lib/registry/registry.js +147 -163
  68. package/lib/registry/service/parseAction.js +16 -16
  69. package/lib/registry/service/parseEvent.js +18 -18
  70. package/lib/registry/service/reduceMixins.js +10 -10
  71. package/lib/registry/service/service.js +72 -72
  72. package/lib/registry/{service-item.js → serviceItem.js} +21 -21
  73. package/lib/runtime/{init-action-invoker.js → initActionInvoker.js} +21 -21
  74. package/lib/runtime/initCache.js +19 -0
  75. package/lib/runtime/{init-context-factory.js → initContextFactory.js} +22 -22
  76. package/lib/runtime/{init-eventbus.js → initEventbus.js} +54 -53
  77. package/lib/runtime/{init-logger.js → initLogger.js} +11 -11
  78. package/lib/runtime/{init-metrics.js → initMetrics.js} +55 -54
  79. package/lib/runtime/{init-middleware-manager.js → initMiddlewareManager.js} +21 -21
  80. package/lib/runtime/{init-registry.js → initRegistry.js} +6 -6
  81. package/lib/runtime/initServiceManager.js +145 -0
  82. package/lib/runtime/{init-tracing.js → initTracing.js} +25 -24
  83. package/lib/runtime/{init-transport.js → initTransport.js} +5 -5
  84. package/lib/runtime/{init-uuid-factory.js → initUuidFactory.js} +4 -4
  85. package/lib/runtime/{init-validator.js → initValidator.js} +5 -5
  86. package/lib/tracing/collectors/base.js +29 -37
  87. package/lib/tracing/collectors/event.js +33 -33
  88. package/lib/tracing/collectors/index.js +16 -16
  89. package/lib/tracing/span.js +34 -32
  90. package/lib/tracing/time.js +8 -8
  91. package/lib/transport/InboundTransformStream.js +75 -0
  92. package/lib/transport/adapters/adapteBase.js +107 -0
  93. package/lib/transport/adapters/adapters.js +4 -4
  94. package/lib/transport/adapters/dummy/index.js +19 -19
  95. package/lib/transport/adapters/fromURI.js +13 -13
  96. package/lib/transport/adapters/getAdapterByName.js +5 -5
  97. package/lib/transport/adapters/index.js +12 -12
  98. package/lib/transport/adapters/tcp/discovery/codec.js +4 -4
  99. package/lib/transport/adapters/tcp/discovery/index.js +90 -76
  100. package/lib/transport/adapters/tcp/index.js +180 -175
  101. package/lib/transport/adapters/tcp/tcp-messagetypes.js +7 -7
  102. package/lib/transport/adapters/tcp/tcpReader.js +39 -38
  103. package/lib/transport/adapters/tcp/tcpWriteStream.js +26 -26
  104. package/lib/transport/adapters/tcp/tcpWriter.js +58 -58
  105. package/lib/transport/adapters/tcp/utils.js +12 -12
  106. package/lib/transport/createMessage.js +11 -0
  107. package/lib/transport/createTransport.js +377 -334
  108. package/lib/transport/errorPayloadFactory.js +15 -0
  109. package/lib/transport/messageHandlers.js +517 -0
  110. package/lib/transport/messageTypes.js +23 -0
  111. package/lib/types.js +95 -71
  112. package/lib/utils/index.js +2 -2
  113. package/lib/utils/options.js +47 -45
  114. package/lib/utils/{restore-error.js → restoreError.js} +4 -4
  115. package/package.json +6 -12
  116. package/CHANGELOG.md +0 -1334
  117. package/lib/build-runtime.js +0 -70
  118. package/lib/cache/base.js +0 -142
  119. package/lib/cache/index.js +0 -48
  120. package/lib/cache/memory.js +0 -121
  121. package/lib/middlewares/tracing/buildTags.js +0 -17
  122. package/lib/new-errors.js +0 -25
  123. package/lib/registry/event-endpoint.js +0 -26
  124. package/lib/runtime/init-cache.js +0 -10
  125. package/lib/runtime/init-service-manager.js +0 -128
  126. package/lib/tracing/collectors/console.js +0 -34
  127. package/lib/tracing/index.js +0 -3
  128. package/lib/tracing/tracer.js +0 -64
  129. package/lib/transport/adapters/adapter-base.js +0 -92
  130. package/lib/transport/message-handlers.js +0 -448
  131. package/lib/transport/message-types.js +0 -59
  132. package/lib/transport/message.js +0 -16
@@ -0,0 +1,70 @@
1
+ /**
2
+ * @typedef {import('./types.js').BrokerOptions} BrokerOptions
3
+ * @typedef {import('./types.js').Runtime} Runtime
4
+ * @typedef {import('./types.js').Broker} Broker
5
+ */
6
+
7
+ const { initLogger } = require('./runtime/initLogger');
8
+ const { initMiddlewareHandler } = require('./runtime/initMiddlewareManager');
9
+ const { initRegistry } = require('./runtime/initRegistry');
10
+ const { initContextFactory } = require('./runtime/initContextFactory');
11
+ const { initEventbus } = require('./runtime/initEventbus');
12
+ const { initValidator } = require('./runtime/initValidator');
13
+ const { initTransport } = require('./runtime/initTransport');
14
+ const { initCache } = require('./runtime/initCache');
15
+ const { initActionInvoker } = require('./runtime/initActionInvoker');
16
+ const { initServiceManager } = require('./runtime/initServiceManager');
17
+ const { initMetrics } = require('./runtime/initMetrics');
18
+ const { initTracer } = require('./runtime/initTracing');
19
+ const { initUUIDFactory } = require('./runtime/initUuidFactory');
20
+ const { errorHandler, fatalErrorHandler } = require('./errorHandler');
21
+ const { uuid } = require('@weave-js/utils');
22
+ const { version } = require('../package.json');
23
+ const EventEmitter = require('eventemitter2');
24
+
25
+ /**
26
+ * Build runtime object
27
+ * @param {BrokerOptions} options Broker options
28
+ * @return {Runtime} Runtime
29
+ */
30
+ exports.initRuntime = (options) => {
31
+ /**
32
+ * Event bus
33
+ * @returns {EventEmitter} Service object.
34
+ */
35
+ const bus = new EventEmitter({
36
+ wildcard: true,
37
+ maxListeners: 1000
38
+ });
39
+
40
+ // Create base runtime object
41
+ const runtime = {
42
+ nodeId: options.nodeId,
43
+ version,
44
+ options,
45
+ bus,
46
+ state: {
47
+ instanceId: uuid(),
48
+ isStarted: false
49
+ },
50
+ handleError: (error) => errorHandler(runtime, error),
51
+ fatalError: (message, error, killProcess) => fatalErrorHandler(runtime, message, error, killProcess)
52
+ };
53
+
54
+ // Init modules
55
+ initLogger(runtime);
56
+ initUUIDFactory(runtime);
57
+ initMiddlewareHandler(runtime);
58
+ initRegistry(runtime);
59
+ initContextFactory(runtime);
60
+ initEventbus(runtime);
61
+ initValidator(runtime);
62
+ initTransport(runtime);
63
+ initCache(runtime);
64
+ initActionInvoker(runtime);
65
+ initServiceManager(runtime);
66
+ initMetrics(runtime);
67
+ initTracer(runtime);
68
+
69
+ return runtime;
70
+ };
@@ -0,0 +1,119 @@
1
+ /*
2
+ * Author: Kevin Ries (kevin.ries@fachwerk.io)
3
+ * -----
4
+ * Copyright 2021 Fachwerk
5
+ */
6
+ const crypto = require('crypto');
7
+ const { isObject, isString } = require('@weave-js/utils');
8
+ const Constants = require('../../metrics/constants');
9
+ const { WeaveError } = require('../../errors');
10
+ const { getCacheKeyByObject } = require('../getCacheKeyByObject');
11
+ const { getPropertyFromDataOrMetadata } = require('../getPropertyFromDataOrMetadata');
12
+
13
+ function generateHash (key) {
14
+ return crypto
15
+ .createHash('sha1')
16
+ .update(key)
17
+ .digest('base64');
18
+ }
19
+
20
+ function registerCacheMetrics (metrics) {
21
+ metrics.register({ type: 'counter', name: Constants.CACHE_GET_TOTAL });
22
+ metrics.register({ type: 'counter', name: Constants.CACHE_SET_TOTAL });
23
+ metrics.register({ type: 'counter', name: Constants.CACHE_FOUND_TOTAL });
24
+ metrics.register({ type: 'counter', name: Constants.CACHE_EXPIRED_TOTAL });
25
+ metrics.register({ type: 'counter', name: Constants.CACHE_DELETED_TOTAL });
26
+ metrics.register({ type: 'counter', name: Constants.CACHE_CLEANED_TOTAL });
27
+ }
28
+
29
+ const createCacheBase = (name, runtime, adapterOptions, options) => {
30
+ if (!isString(name)) {
31
+ throw new WeaveError('Name must be a string.');
32
+ }
33
+
34
+ const cache = {
35
+ name,
36
+ isConnected: false,
37
+ runtime,
38
+ options: Object.assign({
39
+ ttl: null
40
+ }, options),
41
+ init () {
42
+ // register metrics
43
+ if (runtime.metrics) {
44
+ this.metrics = runtime.metrics;
45
+ registerCacheMetrics(runtime.metrics);
46
+ }
47
+ },
48
+ log: runtime.createLogger('CACHER'),
49
+ set (/* hashKey, result, ttl */) {
50
+ /* istanbul ignore next */
51
+ runtime.handleError(new Error('Method not implemented.'));
52
+ },
53
+ get (/* hashKey */) {
54
+ /* istanbul ignore next */
55
+ runtime.handleError(new Error('Method not implemented.'));
56
+ },
57
+ remove () {
58
+ /* istanbul ignore next */
59
+ runtime.handleError(new Error('Method not implemented.'));
60
+ },
61
+ clear () {
62
+ /* istanbul ignore next */
63
+ runtime.handleError(new Error('Method not implemented.'));
64
+ },
65
+ stop () {
66
+ /* istanbul ignore next */
67
+ return Promise.resolve();
68
+ },
69
+ /**
70
+ * Generates a caching key for action data/metadata.
71
+ * @param {string} actionName Namme of the action
72
+ * @param {any} data Data
73
+ * @param {object=} metadata Metadata
74
+ * @param {Array<string>=} keys Key array
75
+ * @returns {string} Result key string
76
+ */
77
+ getCachingKey (actionName, data, metadata, keys) {
78
+ if (data || metadata) {
79
+ const prefix = actionName + '.';
80
+
81
+ if (keys) {
82
+ // fast path for single keys
83
+ if (keys.length === 1) {
84
+ const cacheKeyData = getPropertyFromDataOrMetadata(data, metadata, keys[0]);
85
+ const key = getCacheKeyByObject(cacheKeyData);
86
+ const value = prefix + (isObject(cacheKeyData) ? key : cacheKeyData);
87
+ return prefix + generateHash(value);
88
+ }
89
+
90
+ // Handle data cache keys
91
+ if (keys.length > 0) {
92
+ const valueString = keys.reduce((pre, property, index) => {
93
+ let value = getPropertyFromDataOrMetadata(data, metadata, property);
94
+ value = getCacheKeyByObject(value);
95
+
96
+ return pre + (index > 0 ? '|' : '') + value;
97
+ }, prefix);
98
+
99
+ return prefix + generateHash(valueString);
100
+ }
101
+ } else {
102
+ const value = getCacheKeyByObject(data);
103
+ return prefix + generateHash(value);
104
+ }
105
+ }
106
+
107
+ return actionName;
108
+ }
109
+ };
110
+
111
+ Object.defineProperty(cache, 'adapterOptions', {
112
+ value: adapterOptions,
113
+ writable: false
114
+ });
115
+
116
+ return cache;
117
+ };
118
+
119
+ module.exports = { createCacheBase };
@@ -0,0 +1,154 @@
1
+ /*
2
+ * Author: Kevin Ries (kevin.ries@fachwerk.io)
3
+ * -----
4
+ * Copyright 2021 Fachwerk
5
+ */
6
+
7
+ const { match, defaultsDeep } = require('@weave-js/utils');
8
+ const { createCacheBase } = require('./base');
9
+ const { createLock } = require('../lock');
10
+ const Constants = require('../../metrics/constants');
11
+
12
+ const defaultAdapterOptions = {
13
+ ttlCheckInterval: 3000
14
+ };
15
+
16
+ /**
17
+ * @typedef {Object} InMemoryAdapterOptions
18
+ * @property {number=} ttlCheckInterval TTL check interval
19
+ */
20
+
21
+ /**
22
+ * Create an in-memory cache adapter.
23
+ * @param {InMemoryAdapterOptions} adapterOptions Adapter options
24
+ * @returns {any} CacheFactory
25
+ */
26
+ const createInMemoryCache = (adapterOptions = {}) => (runtime, options = {}) => {
27
+ adapterOptions = defaultsDeep(adapterOptions, defaultAdapterOptions);
28
+ const base = createCacheBase('In-Memory', runtime, adapterOptions, options);
29
+ const storage = new Map();
30
+
31
+ const lock = createLock();
32
+
33
+ const ttlTimerHandle = setInterval(() => {
34
+ checkTtl();
35
+ }, adapterOptions.ttlCheckInterval);
36
+
37
+ ttlTimerHandle.unref();
38
+
39
+ // if a new broker gets connected, we need to clear the cache
40
+ runtime.bus.on('$transport.connected', () => {
41
+ base.log.debug('Transport adapter connected. Cache will be cleared.');
42
+ cache.clear();
43
+ });
44
+
45
+ const checkTtl = () => {
46
+ const now = Date.now();
47
+
48
+ storage.forEach((item, hashKey) => {
49
+ if (item.expire && item.expire < now) {
50
+ cache.log.debug(`Delete ${hashKey}`);
51
+ storage.delete(hashKey);
52
+ }
53
+ });
54
+ };
55
+
56
+ const cache = Object.assign(
57
+ {},
58
+ base,
59
+ {
60
+ init () {
61
+ base.init();
62
+ cache.isConnected = true;
63
+ },
64
+ get (cacheKey) {
65
+ base.log.debug(`Get ${cacheKey}`);
66
+
67
+ if (base.metrics) {
68
+ base.metrics.increment(Constants.CACHE_GET_TOTAL);
69
+ }
70
+
71
+ const item = storage.get(cacheKey);
72
+
73
+ if (item) {
74
+ cache.log.debug(`Found ${cacheKey}`);
75
+
76
+ if (base.metrics) {
77
+ base.metrics.increment(Constants.CACHE_FOUND_TOTAL);
78
+ }
79
+
80
+ if (item.expire && item.expire < Date.now()) {
81
+ cache.log.debug(`Delete ${cacheKey}`);
82
+ storage.delete(cacheKey);
83
+ if (base.metrics) {
84
+ base.metrics.increment(Constants.CACHE_EXPIRED_TOTAL);
85
+ }
86
+ return Promise.resolve(null);
87
+ }
88
+
89
+ return Promise.resolve(item.data);
90
+ }
91
+ return Promise.resolve(null);
92
+ },
93
+ set (hashKey, data, ttl) {
94
+ if (base.metrics) {
95
+ base.metrics.increment(Constants.CACHE_SET_TOTAL);
96
+ }
97
+
98
+ // if ttl is not set in action cache settings, use options ttl
99
+ if (ttl == null) {
100
+ ttl = options.ttl;
101
+ }
102
+
103
+ storage.set(hashKey, {
104
+ data,
105
+ expire: ttl ? Date.now() + ttl : null
106
+ });
107
+
108
+ base.log.debug(`Set ${hashKey}`);
109
+
110
+ return Promise.resolve(data);
111
+ },
112
+ remove (hashKey) {
113
+ if (base.metrics) {
114
+ base.metrics.increment(Constants.CACHE_DELETED_TOTAL);
115
+ }
116
+ storage.delete(hashKey);
117
+ base.log.debug(`Delete cached object with key ${hashKey}`);
118
+
119
+ return Promise.resolve();
120
+ },
121
+ clear (pattern = '**') {
122
+ if (base.metrics) {
123
+ base.metrics.increment(Constants.CACHE_DELETED_TOTAL);
124
+ }
125
+
126
+ storage.forEach((_, key) => {
127
+ if (match(key, pattern)) {
128
+ this.remove(key);
129
+ }
130
+ });
131
+ return Promise.resolve();
132
+ },
133
+ lock (key, ttl) {
134
+ return lock.acquire(key, ttl).then(() => {
135
+ return () => lock.release(key);
136
+ });
137
+ },
138
+ tryAcquireLock (key, ttl) {
139
+ if (lock.isLocked(key)) {
140
+ return Promise.reject(new Error('Locked'));
141
+ }
142
+
143
+ return lock.acquire(key, ttl).then(() => {
144
+ return () => lock.release(key);
145
+ });
146
+ },
147
+ async stop () {
148
+ clearInterval(ttlTimerHandle);
149
+ }
150
+ });
151
+ return cache;
152
+ };
153
+
154
+ module.exports = { createInMemoryCache };
@@ -0,0 +1,140 @@
1
+ /*
2
+ * Author: Kevin Ries (kevin.ries@fachwerk.io)
3
+ * -----
4
+ * Copyright 2021 Fachwerk
5
+ */
6
+
7
+ const { match } = require('@weave-js/utils');
8
+ const { createCacheBase } = require('./base');
9
+ const { createLock } = require('../lock');
10
+ const Constants = require('../../metrics/constants');
11
+
12
+ const createInMemoryLruCache = (adapterOptions) => (runtime, options = {}) => {
13
+ const name = 'In-Memory';
14
+ const base = createCacheBase(name, runtime, options);
15
+ const storage = new Map();
16
+
17
+ const lock = createLock();
18
+
19
+ const timer = setInterval(() => {
20
+ checkTtl();
21
+ }, 3000);
22
+
23
+ timer.unref();
24
+
25
+ // if a new broker gets connected, we need to clear the cache
26
+ runtime.bus.on('$transport.connected', () => {
27
+ base.log.debug('Transport adapter connected. Cache will be cleared.');
28
+ cache.clear();
29
+ });
30
+
31
+ const checkTtl = () => {
32
+ const now = Date.now();
33
+
34
+ storage.forEach((item, hashKey) => {
35
+ if (item.expire && item.expire < now) {
36
+ cache.log.debug(`Delete ${hashKey}`);
37
+ storage.delete(hashKey);
38
+ }
39
+ });
40
+ };
41
+
42
+ const cache = Object.assign(
43
+ {},
44
+ base,
45
+ {
46
+ name,
47
+ init () {
48
+ base.init();
49
+ cache.isConnected = true;
50
+ },
51
+ get (cacheKey) {
52
+ base.log.debug(`Get ${cacheKey}`);
53
+
54
+ if (base.metrics) {
55
+ base.metrics.increment(Constants.CACHE_GET_TOTAL);
56
+ }
57
+
58
+ const item = storage.get(cacheKey);
59
+
60
+ if (item) {
61
+ cache.log.debug(`Found ${cacheKey}`);
62
+
63
+ if (base.metrics) {
64
+ base.metrics.increment(Constants.CACHE_FOUND_TOTAL);
65
+ }
66
+
67
+ if (item.expire && item.expire < Date.now()) {
68
+ cache.log.debug(`Delete ${cacheKey}`);
69
+ storage.delete(cacheKey);
70
+ if (base.metrics) {
71
+ base.metrics.increment(Constants.CACHE_EXPIRED_TOTAL);
72
+ }
73
+ return Promise.resolve(null);
74
+ }
75
+
76
+ return Promise.resolve(item.data);
77
+ }
78
+ return Promise.resolve(null);
79
+ },
80
+ set (hashKey, data, ttl) {
81
+ if (base.metrics) {
82
+ base.metrics.increment(Constants.CACHE_SET_TOTAL);
83
+ }
84
+
85
+ if (ttl == null) {
86
+ ttl = options.ttl;
87
+ }
88
+
89
+ storage.set(hashKey, {
90
+ data,
91
+ expire: ttl ? Date.now() + ttl : null
92
+ });
93
+
94
+ base.log.debug(`Set ${hashKey}`);
95
+
96
+ return Promise.resolve(data);
97
+ },
98
+ remove (hashKey) {
99
+ if (base.metrics) {
100
+ base.metrics.increment(Constants.CACHE_DELETED_TOTAL);
101
+ }
102
+ storage.delete(hashKey);
103
+ base.log.debug(`Delete ${hashKey}`);
104
+
105
+ return Promise.resolve();
106
+ },
107
+ clear (pattern = '**') {
108
+ if (base.metrics) {
109
+ base.metrics.increment(Constants.CACHE_DELETED_TOTAL);
110
+ }
111
+ storage.forEach((_, key) => {
112
+ if (match(key, pattern)) {
113
+ base.log.debug(`Delete ${key}`);
114
+ this.remove(key);
115
+ }
116
+ });
117
+ return Promise.resolve();
118
+ },
119
+ lock (key, ttl) {
120
+ return lock.acquire(key, ttl).then(() => {
121
+ return () => lock.release(key);
122
+ });
123
+ },
124
+ tryAcquireLock (key, ttl) {
125
+ if (lock.isLocked(key)) {
126
+ return Promise.reject(new Error('Locked'));
127
+ }
128
+
129
+ return lock.acquire(key, ttl).then(() => {
130
+ return () => lock.release(key);
131
+ });
132
+ },
133
+ stop () {
134
+ clearInterval(timer);
135
+ }
136
+ });
137
+ return cache;
138
+ };
139
+
140
+ module.exports = { createInMemoryLruCache };
@@ -0,0 +1,10 @@
1
+ /*
2
+ * Author: Kevin Ries (kevin.ries@fachwerk.io)
3
+ * -----
4
+ * Copyright 2021 Fachwerk
5
+ */
6
+
7
+ module.exports = {
8
+ ...require('./base'),
9
+ ...require('./inMemory')
10
+ };
@@ -0,0 +1,31 @@
1
+ const { isObject, isString } = require('@weave-js/utils');
2
+
3
+ /**
4
+ * Get property from data or metadata object.
5
+ * @param {any} value Value
6
+ * @returns {string} Cache key
7
+ */
8
+ const getCacheKeyByObject = (value) => {
9
+ if (Array.isArray(value)) {
10
+ return '[' + value.map(object => getCacheKeyByObject(object)).join(',') + ']';
11
+ } else if (isObject(value)) {
12
+ // Handle date objects
13
+ if (value instanceof Date) {
14
+ return value.toISOString();
15
+ }
16
+
17
+ return '{' + Object.keys(value)
18
+ .map((key) => {
19
+ return [key, getCacheKeyByObject(value[key])].join(':');
20
+ })
21
+ .join(',') + '}';
22
+ } else if (isString(value)) {
23
+ return value;
24
+ } else if (typeof value === 'boolean' || typeof value === 'number') {
25
+ return value.toString();
26
+ } else {
27
+ return 'null';
28
+ }
29
+ };
30
+
31
+ module.exports = { getCacheKeyByObject };
@@ -0,0 +1,20 @@
1
+ const { dotGet } = require('@weave-js/utils');
2
+
3
+ /**
4
+ * Get property from data or metadata object.
5
+ * @param {any} data data object
6
+ * @param {object} metadata metadata object
7
+ * @param {string} key key
8
+ * @returns {any} Result
9
+ */
10
+ const getPropertyFromDataOrMetadata = (data, metadata, key) => {
11
+ // if a key starts with ":", the property is picked from metadata
12
+ if (key.startsWith(':')) {
13
+ // remove ':' from key.
14
+ key = key.replace(':', '');
15
+ return dotGet(metadata, key);
16
+ }
17
+ return dotGet(data, key);
18
+ };
19
+
20
+ module.exports = { getPropertyFromDataOrMetadata };
package/lib/cache/lock.js CHANGED
@@ -1,14 +1,37 @@
1
- exports.ttlcreateLock = () => {
2
- const locked = new Map()
3
- return {
4
- acquire (key, ttl) {
5
- const lock = locked.get(key)
6
- if (!lock) {
7
- lock.set(key, [])
1
+ const createLock = () => {
2
+ const locked = new Map();
3
+
4
+ function acquire (key, ttl) {
5
+ const lockedItems = locked.get(key);
6
+ if (!lockedItems) {
7
+ locked.set(key, []);
8
+ return Promise.resolve();
9
+ } else {
10
+ return new Promise((resolve) => lockedItems.push(resolve));
11
+ }
12
+ }
13
+
14
+ function isLocked (key) {
15
+ return !!locked.has(key);
16
+ }
17
+
18
+ function release (key) {
19
+ const lockedItems = locked.get(key);
20
+ if (lockedItems) {
21
+ if (lockedItems.length > 0) {
22
+ lockedItems.shift()();
23
+ } else {
24
+ locked.delete(key);
8
25
  }
9
- },
10
- isLocked (key) {
11
- return !!locked.has(key)
12
26
  }
27
+ return Promise.resolve();
13
28
  }
14
- }
29
+
30
+ return Object.freeze({
31
+ acquire,
32
+ isLocked,
33
+ release
34
+ });
35
+ };
36
+
37
+ module.exports = { createLock };
package/lib/constants.js CHANGED
@@ -1,15 +1,22 @@
1
1
  /*
2
- * Author: Kevin Ries (kevin@fachw3rk.de)
2
+ * Author: Kevin Ries (kevin.ries@fachwerk.io)
3
3
  * -----
4
4
  * Copyright 2021 Fachwerk
5
5
  */
6
6
 
7
- exports.PROTOCOL_VERSION = 1
7
+ exports.PROTOCOL_VERSION = 1;
8
8
 
9
9
  exports.loadBalancingStrategy = {
10
10
  ROUND_ROBIN: 'round_robin',
11
11
  RANDOM: 'random'
12
- }
12
+ };
13
+
14
+ exports.circuitBreakerStates = {
15
+ CIRCUIT_CLOSED: 'closed',
16
+ CIRCUIT_HALF_OPENED: 'half_opened',
17
+ CIRCUIT_HALF_OPEN_WAITING: 'half_open_waiting',
18
+ CIRCUIT_OPENED: 'opened'
19
+ };
13
20
 
14
21
  exports.level = {
15
22
  trace: 'trace',
@@ -18,8 +25,4 @@ exports.level = {
18
25
  warn: 'warn',
19
26
  error: 'error',
20
27
  fatal: 'fatal'
21
- }
22
-
23
- exports.SYNC_MIDDLEWARE_HOOKS = {
24
- STARTING: 'starting'
25
- }
28
+ };
@@ -1,19 +1,19 @@
1
1
  exports.errorHandler = ({ options }, error) => {
2
2
  if (options.errorHandler) {
3
- return options.errorHandler.call(null, error)
3
+ return options.errorHandler.call(null, error);
4
4
  }
5
- throw error
6
- }
5
+ throw error;
6
+ };
7
7
 
8
8
  exports.fatalErrorHandler = (runtime, message, error, killProcess = true) => {
9
- const { options, log } = runtime
9
+ const { options, log } = runtime;
10
10
  if (options.logger.enabled) {
11
- log.fatal(error, message)
11
+ log.fatal(error, message);
12
12
  } else {
13
- console.error(message, error)
13
+ console.error(message, error);
14
14
  }
15
15
 
16
16
  if (killProcess) {
17
- process.exit(1)
17
+ process.exit(1);
18
18
  }
19
- }
19
+ };