@tramvai/module-common 4.36.2 → 4.38.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.
package/README.md CHANGED
@@ -65,12 +65,89 @@ Module that implements caches.
65
65
 
66
66
  It provides next functionality:
67
67
 
68
- - create new cache instance (currently it will be instance of lru-cache)
68
+ - create new cache instance (instance of lru-cache by default)
69
69
  - clear all of the previously create caches
70
70
  - subscribe on cache clearance event to execute own cache clearance actions
71
71
  - adds papi-route `/clear-cache` that will trigger caches clear event
72
72
 
73
- This modules logs wit id `cache:papi-clear-cache`
73
+ This modules logs with id `cache:papi-clear-cache`
74
+
75
+ ##### Cache types
76
+
77
+ You can create different cache types with `CREATE_CACHE_TOKEN` factory:
78
+
79
+ - LRU - [@tinkoff/lru-cache-nano](https://github.com/tramvaijs/lru-cache-nano)
80
+
81
+ This type of cache is created by default. To create it explicitly you must pass `'memory'` as the first argument, and options as the second.
82
+
83
+ ```typescript
84
+ provide({
85
+ provide: CACHE_TOKEN,
86
+ scope: Scope.SINGLETON,
87
+ useFactory: ({ createCache }) =>
88
+ createCache('memory', {
89
+ max: 100,
90
+ ttl: 24 * 60 * 60 * 1000, // 1 day
91
+ ttlResolution: 60 * 1000, // 1 minute
92
+ allowStale: true,
93
+ updateAgeOnGet: true,
94
+ }),
95
+ deps: {
96
+ createCache: CREATE_CACHE_TOKEN,
97
+ },
98
+ });
99
+ ```
100
+
101
+ - LFU - [@akashbabu/lfu-cache](https://github.com/AkashBabu/lfu-cache)
102
+
103
+ To create it you must pass `'memory-lfu'` as the first argument, cache options - as second.
104
+
105
+ ```typescript
106
+ provide({
107
+ provide: CACHE_TOKEN,
108
+ scope: Scope.SINGLETON,
109
+ useFactory: ({ createCache }) =>
110
+ createCache('memory-lfu', {
111
+ max: 20,
112
+ evictCount: 5,
113
+ maxAge: 24 * 60 * 60 * 1000, // 1 day
114
+ }),
115
+ deps: {
116
+ createCache: CREATE_CACHE_TOKEN,
117
+ },
118
+ });
119
+ ```
120
+
121
+ ##### Cache metrics
122
+
123
+ To turn cache hit/miss rate monitoring, cache size, you need to provide cache name in options:
124
+
125
+ ```typescript
126
+ provide({
127
+ provide: CACHE_TOKEN,
128
+ scope: Scope.SINGLETON,
129
+ useFactory: ({ createCache }) =>
130
+ createCache('memory', {
131
+ name: 'cache-name',
132
+ }),
133
+ deps: {
134
+ createCache: CREATE_CACHE_TOKEN,
135
+ },
136
+ });
137
+ ```
138
+
139
+ Cache name have to be unique, factory will throw exception in case of cache name duplication.
140
+
141
+ [Metric module](references/modules/metrics.md) should be provided in your application.
142
+
143
+ Server cache metrics:
144
+
145
+ - cache_hit{name, method} counter
146
+ - cache_miss{name, method} counter
147
+ - cache_max{name} gauge
148
+ - cache_size{name} gauge
149
+
150
+ By default hit/miss rate is computed as a sum of all data access attempts (methods `has`, `peek`, `get`).
74
151
 
75
152
  #### RequestManagerModule
76
153
 
@@ -1,11 +1,11 @@
1
1
  import { __decorate } from 'tslib';
2
- import { createToken } from '@tinkoff/dippy';
2
+ import { provide } from '@tinkoff/dippy';
3
3
  import { Module, Scope } from '@tramvai/core';
4
- import { CREATE_CACHE_TOKEN, CLEAR_CACHE_TOKEN, REGISTER_CLEAR_CACHE_TOKEN } from '@tramvai/tokens-common';
5
- import { cacheFactory } from './cacheFactory.browser.browser.js';
4
+ import { CREATE_CACHE_TOKEN, CACHE_METRICS_SERVER_TOKEN, CLEAR_CACHE_TOKEN, REGISTER_CLEAR_CACHE_TOKEN } from '@tramvai/tokens-common';
6
5
  import { providers } from './clientProviders.browser.js';
6
+ import { cacheRegistry } from './cacheRegistry.browser.js';
7
+ import { CACHES_LIST_TOKEN, CACHE_NAMES_LIST_TOKEN } from './tokens.browser.js';
7
8
 
8
- const cachesToken = createToken('_cachesList');
9
9
  let CacheModule = class CacheModule {
10
10
  };
11
11
  CacheModule = __decorate([
@@ -13,43 +13,45 @@ CacheModule = __decorate([
13
13
  providers: [
14
14
  ...providers,
15
15
  {
16
- provide: cachesToken,
16
+ provide: CACHES_LIST_TOKEN,
17
17
  scope: Scope.SINGLETON,
18
18
  useValue: [],
19
19
  },
20
- {
20
+ provide({
21
21
  provide: CREATE_CACHE_TOKEN,
22
22
  scope: Scope.SINGLETON,
23
- useFactory: ({ caches }) => {
24
- return (type, ...args) => {
25
- const cache = cacheFactory(type, ...args);
26
- caches.push(cache);
27
- return cache;
28
- };
29
- },
23
+ useFactory: cacheRegistry,
30
24
  deps: {
31
- caches: cachesToken,
25
+ caches: CACHES_LIST_TOKEN,
26
+ cacheNames: {
27
+ token: CACHE_NAMES_LIST_TOKEN,
28
+ optional: true,
29
+ },
30
+ metrics: {
31
+ token: CACHE_METRICS_SERVER_TOKEN,
32
+ optional: true,
33
+ },
32
34
  },
33
- },
34
- {
35
+ }),
36
+ provide({
35
37
  provide: CLEAR_CACHE_TOKEN,
36
38
  scope: Scope.SINGLETON,
37
- useFactory: ({ caches, cachesClear }) => {
39
+ useFactory: ({ caches, onCacheClear }) => {
38
40
  return (type) => {
39
41
  caches.forEach((cache) => cache.clear());
40
- if (cachesClear) {
41
- return Promise.all(cachesClear.map((clear) => clear(type)));
42
+ if (onCacheClear) {
43
+ return Promise.all(onCacheClear.map((clear) => clear(type)));
42
44
  }
43
45
  return Promise.resolve();
44
46
  };
45
47
  },
46
48
  deps: {
47
- caches: cachesToken,
48
- cachesClear: { token: REGISTER_CLEAR_CACHE_TOKEN, optional: true },
49
+ caches: CACHES_LIST_TOKEN,
50
+ onCacheClear: { token: REGISTER_CLEAR_CACHE_TOKEN, optional: true },
49
51
  },
50
- },
52
+ }),
51
53
  ],
52
54
  })
53
55
  ], CacheModule);
54
56
 
55
- export { CacheModule, cachesToken };
57
+ export { CacheModule };
@@ -1,7 +1,3 @@
1
- import type { Cache } from '@tramvai/tokens-common';
2
- export declare const cachesToken: Cache<any>[] & {
3
- __type?: "base token" | undefined;
4
- };
5
1
  export declare class CacheModule {
6
2
  }
7
3
  //# sourceMappingURL=CacheModule.d.ts.map
@@ -1,11 +1,11 @@
1
1
  import { __decorate } from 'tslib';
2
- import { createToken } from '@tinkoff/dippy';
2
+ import { provide } from '@tinkoff/dippy';
3
3
  import { Module, Scope } from '@tramvai/core';
4
- import { CREATE_CACHE_TOKEN, CLEAR_CACHE_TOKEN, REGISTER_CLEAR_CACHE_TOKEN } from '@tramvai/tokens-common';
5
- import { cacheFactory } from './cacheFactory.es.js';
4
+ import { CREATE_CACHE_TOKEN, CACHE_METRICS_SERVER_TOKEN, CLEAR_CACHE_TOKEN, REGISTER_CLEAR_CACHE_TOKEN } from '@tramvai/tokens-common';
6
5
  import { providers } from './serverProviders.es.js';
6
+ import { cacheRegistry } from './cacheRegistry.es.js';
7
+ import { CACHES_LIST_TOKEN, CACHE_NAMES_LIST_TOKEN } from './tokens.es.js';
7
8
 
8
- const cachesToken = createToken('_cachesList');
9
9
  let CacheModule = class CacheModule {
10
10
  };
11
11
  CacheModule = __decorate([
@@ -13,43 +13,45 @@ CacheModule = __decorate([
13
13
  providers: [
14
14
  ...providers,
15
15
  {
16
- provide: cachesToken,
16
+ provide: CACHES_LIST_TOKEN,
17
17
  scope: Scope.SINGLETON,
18
18
  useValue: [],
19
19
  },
20
- {
20
+ provide({
21
21
  provide: CREATE_CACHE_TOKEN,
22
22
  scope: Scope.SINGLETON,
23
- useFactory: ({ caches }) => {
24
- return (type, ...args) => {
25
- const cache = cacheFactory(type, ...args);
26
- caches.push(cache);
27
- return cache;
28
- };
29
- },
23
+ useFactory: cacheRegistry,
30
24
  deps: {
31
- caches: cachesToken,
25
+ caches: CACHES_LIST_TOKEN,
26
+ cacheNames: {
27
+ token: CACHE_NAMES_LIST_TOKEN,
28
+ optional: true,
29
+ },
30
+ metrics: {
31
+ token: CACHE_METRICS_SERVER_TOKEN,
32
+ optional: true,
33
+ },
32
34
  },
33
- },
34
- {
35
+ }),
36
+ provide({
35
37
  provide: CLEAR_CACHE_TOKEN,
36
38
  scope: Scope.SINGLETON,
37
- useFactory: ({ caches, cachesClear }) => {
39
+ useFactory: ({ caches, onCacheClear }) => {
38
40
  return (type) => {
39
41
  caches.forEach((cache) => cache.clear());
40
- if (cachesClear) {
41
- return Promise.all(cachesClear.map((clear) => clear(type)));
42
+ if (onCacheClear) {
43
+ return Promise.all(onCacheClear.map((clear) => clear(type)));
42
44
  }
43
45
  return Promise.resolve();
44
46
  };
45
47
  },
46
48
  deps: {
47
- caches: cachesToken,
48
- cachesClear: { token: REGISTER_CLEAR_CACHE_TOKEN, optional: true },
49
+ caches: CACHES_LIST_TOKEN,
50
+ onCacheClear: { token: REGISTER_CLEAR_CACHE_TOKEN, optional: true },
49
51
  },
50
- },
52
+ }),
51
53
  ],
52
54
  })
53
55
  ], CacheModule);
54
56
 
55
- export { CacheModule, cachesToken };
57
+ export { CacheModule };
@@ -6,10 +6,10 @@ var tslib = require('tslib');
6
6
  var dippy = require('@tinkoff/dippy');
7
7
  var core = require('@tramvai/core');
8
8
  var tokensCommon = require('@tramvai/tokens-common');
9
- var cacheFactory = require('./cacheFactory.js');
10
9
  var serverProviders = require('./serverProviders.js');
10
+ var cacheRegistry = require('./cacheRegistry.js');
11
+ var tokens = require('./tokens.js');
11
12
 
12
- const cachesToken = dippy.createToken('_cachesList');
13
13
  exports.CacheModule = class CacheModule {
14
14
  };
15
15
  exports.CacheModule = tslib.__decorate([
@@ -17,43 +17,43 @@ exports.CacheModule = tslib.__decorate([
17
17
  providers: [
18
18
  ...serverProviders.providers,
19
19
  {
20
- provide: cachesToken,
20
+ provide: tokens.CACHES_LIST_TOKEN,
21
21
  scope: core.Scope.SINGLETON,
22
22
  useValue: [],
23
23
  },
24
- {
24
+ dippy.provide({
25
25
  provide: tokensCommon.CREATE_CACHE_TOKEN,
26
26
  scope: core.Scope.SINGLETON,
27
- useFactory: ({ caches }) => {
28
- return (type, ...args) => {
29
- const cache = cacheFactory.cacheFactory(type, ...args);
30
- caches.push(cache);
31
- return cache;
32
- };
33
- },
27
+ useFactory: cacheRegistry.cacheRegistry,
34
28
  deps: {
35
- caches: cachesToken,
29
+ caches: tokens.CACHES_LIST_TOKEN,
30
+ cacheNames: {
31
+ token: tokens.CACHE_NAMES_LIST_TOKEN,
32
+ optional: true,
33
+ },
34
+ metrics: {
35
+ token: tokensCommon.CACHE_METRICS_SERVER_TOKEN,
36
+ optional: true,
37
+ },
36
38
  },
37
- },
38
- {
39
+ }),
40
+ dippy.provide({
39
41
  provide: tokensCommon.CLEAR_CACHE_TOKEN,
40
42
  scope: core.Scope.SINGLETON,
41
- useFactory: ({ caches, cachesClear }) => {
43
+ useFactory: ({ caches, onCacheClear }) => {
42
44
  return (type) => {
43
45
  caches.forEach((cache) => cache.clear());
44
- if (cachesClear) {
45
- return Promise.all(cachesClear.map((clear) => clear(type)));
46
+ if (onCacheClear) {
47
+ return Promise.all(onCacheClear.map((clear) => clear(type)));
46
48
  }
47
49
  return Promise.resolve();
48
50
  };
49
51
  },
50
52
  deps: {
51
- caches: cachesToken,
52
- cachesClear: { token: tokensCommon.REGISTER_CLEAR_CACHE_TOKEN, optional: true },
53
+ caches: tokens.CACHES_LIST_TOKEN,
54
+ onCacheClear: { token: tokensCommon.REGISTER_CLEAR_CACHE_TOKEN, optional: true },
53
55
  },
54
- },
56
+ }),
55
57
  ],
56
58
  })
57
59
  ], exports.CacheModule);
58
-
59
- exports.cachesToken = cachesToken;
@@ -1,7 +1,9 @@
1
1
  import LRU from '@tinkoff/lru-cache-nano';
2
2
 
3
- const cacheFactory = (type, options = { max: 100 }) => {
4
- return new LRU(options);
5
- };
3
+ function getCacheFactory() {
4
+ return function cacheFactory(cacheType = 'memory', options) {
5
+ return new LRU(options);
6
+ };
7
+ }
6
8
 
7
- export { cacheFactory };
9
+ export { getCacheFactory };
@@ -1,3 +1,4 @@
1
- import type { CacheFactory } from '@tramvai/tokens-common';
2
- export declare const cacheFactory: CacheFactory;
1
+ import LRU from '@tinkoff/lru-cache-nano';
2
+ import type { CacheOptions, CacheType } from '@tramvai/tokens-common';
3
+ export declare function getCacheFactory(): <T>(cacheType: CacheType | undefined, options: CacheOptions<CacheType>) => LRU<string, T>;
3
4
  //# sourceMappingURL=cacheFactory.browser.d.ts.map
@@ -1,3 +1,6 @@
1
- import type { CacheFactory } from '@tramvai/tokens-common';
2
- export declare const cacheFactory: CacheFactory;
1
+ import type { CacheOptions, Cache, CacheServerMetricsHandlers, CacheType } from '@tramvai/tokens-common';
2
+ export declare function getCacheFactory({ cacheNames, metrics, }: {
3
+ cacheNames: Set<string> | null;
4
+ metrics: CacheServerMetricsHandlers | null;
5
+ }): <T>(cacheType: CacheType, options: CacheOptions<CacheType>) => Cache<T>;
3
6
  //# sourceMappingURL=cacheFactory.d.ts.map
@@ -1,34 +1,60 @@
1
1
  import LRU from '@tinkoff/lru-cache-nano';
2
2
  import LFU from '@akashbabu/lfu-cache';
3
+ import { MEMORY_LRU } from '@tramvai/tokens-common';
4
+ import { isMemoryLFU, isMemoryLRU } from './cacheType.es.js';
5
+ import { CacheWithMetricsProxy } from './cacheWithMetricsProxy.es.js';
3
6
 
4
7
  class LFUToCacheAdapter extends LFU {
5
- set(key, value, options) {
6
- return this.set(key, value);
7
- }
8
8
  has(key) {
9
- return typeof this.get(key) !== 'undefined';
9
+ return typeof super.get(key) !== 'undefined';
10
10
  }
11
11
  dump() {
12
12
  const arr = [];
13
- this.forEach(([key, value]) => arr.push([key, { value }]));
13
+ super.forEach(([key, value]) => arr.push([key, { value }]));
14
14
  return arr;
15
15
  }
16
16
  load(arr) {
17
17
  arr.forEach(([key, { value }]) => {
18
- this.set(key, value);
18
+ super.set(key, value);
19
19
  });
20
20
  }
21
21
  }
22
- const cacheFactory = (type, options = { max: 100 }) => {
23
- if (type === 'memory-lfu') {
24
- if (typeof options === 'object' && 'ttl' in options) {
25
- // ttl option is not supported by @akashbabu/lfu-cache
26
- // eslint-disable-next-line no-param-reassign
27
- options.maxAge = options.ttl;
28
- }
29
- return new LFUToCacheAdapter(options);
30
- }
22
+ function cacheFactoryMemoryLRU({ type, ...options }) {
31
23
  return new LRU(options);
32
- };
24
+ }
25
+ function cacheFactoryMemoryLFU({ type, ...options }) {
26
+ if (options && 'ttl' in options && typeof options.ttl === 'number') {
27
+ // ttl option is not supported by @akashbabu/lfu-cache
28
+ // eslint-disable-next-line no-param-reassign
29
+ options.maxAge = options.ttl;
30
+ }
31
+ return new LFUToCacheAdapter(options);
32
+ }
33
+ function cacheFactory(cacheType = MEMORY_LRU, options) {
34
+ let cache;
35
+ if (isMemoryLFU(options)) {
36
+ cache = cacheFactoryMemoryLFU(options);
37
+ }
38
+ if (isMemoryLRU(options)) {
39
+ cache = cacheFactoryMemoryLRU(options);
40
+ }
41
+ if (!cache) {
42
+ throw new Error(`Cache type ${cacheType} doesn't implemented yet`);
43
+ }
44
+ return cache;
45
+ }
46
+ function getCacheFactory({ cacheNames, metrics, }) {
47
+ return function (cacheType, options) {
48
+ const cache = cacheFactory(cacheType, options);
49
+ if (!(options === null || options === void 0 ? void 0 : options.name) || cacheNames === null) {
50
+ return cache;
51
+ }
52
+ if (cacheNames.has(options.name)) {
53
+ throw new Error(`Cache with name ${options.name} is already created`);
54
+ }
55
+ cacheNames.add(options.name);
56
+ return new CacheWithMetricsProxy(cache, options, metrics);
57
+ };
58
+ }
33
59
 
34
- export { cacheFactory };
60
+ export { getCacheFactory };
@@ -4,6 +4,9 @@ Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var LRU = require('@tinkoff/lru-cache-nano');
6
6
  var LFU = require('@akashbabu/lfu-cache');
7
+ var tokensCommon = require('@tramvai/tokens-common');
8
+ var cacheType = require('./cacheType.js');
9
+ var cacheWithMetricsProxy = require('./cacheWithMetricsProxy.js');
7
10
 
8
11
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
9
12
 
@@ -11,33 +14,56 @@ var LRU__default = /*#__PURE__*/_interopDefaultLegacy(LRU);
11
14
  var LFU__default = /*#__PURE__*/_interopDefaultLegacy(LFU);
12
15
 
13
16
  class LFUToCacheAdapter extends LFU__default["default"] {
14
- set(key, value, options) {
15
- return this.set(key, value);
16
- }
17
17
  has(key) {
18
- return typeof this.get(key) !== 'undefined';
18
+ return typeof super.get(key) !== 'undefined';
19
19
  }
20
20
  dump() {
21
21
  const arr = [];
22
- this.forEach(([key, value]) => arr.push([key, { value }]));
22
+ super.forEach(([key, value]) => arr.push([key, { value }]));
23
23
  return arr;
24
24
  }
25
25
  load(arr) {
26
26
  arr.forEach(([key, { value }]) => {
27
- this.set(key, value);
27
+ super.set(key, value);
28
28
  });
29
29
  }
30
30
  }
31
- const cacheFactory = (type, options = { max: 100 }) => {
32
- if (type === 'memory-lfu') {
33
- if (typeof options === 'object' && 'ttl' in options) {
34
- // ttl option is not supported by @akashbabu/lfu-cache
35
- // eslint-disable-next-line no-param-reassign
36
- options.maxAge = options.ttl;
37
- }
38
- return new LFUToCacheAdapter(options);
39
- }
31
+ function cacheFactoryMemoryLRU({ type, ...options }) {
40
32
  return new LRU__default["default"](options);
41
- };
33
+ }
34
+ function cacheFactoryMemoryLFU({ type, ...options }) {
35
+ if (options && 'ttl' in options && typeof options.ttl === 'number') {
36
+ // ttl option is not supported by @akashbabu/lfu-cache
37
+ // eslint-disable-next-line no-param-reassign
38
+ options.maxAge = options.ttl;
39
+ }
40
+ return new LFUToCacheAdapter(options);
41
+ }
42
+ function cacheFactory(cacheType$1 = tokensCommon.MEMORY_LRU, options) {
43
+ let cache;
44
+ if (cacheType.isMemoryLFU(options)) {
45
+ cache = cacheFactoryMemoryLFU(options);
46
+ }
47
+ if (cacheType.isMemoryLRU(options)) {
48
+ cache = cacheFactoryMemoryLRU(options);
49
+ }
50
+ if (!cache) {
51
+ throw new Error(`Cache type ${cacheType$1} doesn't implemented yet`);
52
+ }
53
+ return cache;
54
+ }
55
+ function getCacheFactory({ cacheNames, metrics, }) {
56
+ return function (cacheType, options) {
57
+ const cache = cacheFactory(cacheType, options);
58
+ if (!(options === null || options === void 0 ? void 0 : options.name) || cacheNames === null) {
59
+ return cache;
60
+ }
61
+ if (cacheNames.has(options.name)) {
62
+ throw new Error(`Cache with name ${options.name} is already created`);
63
+ }
64
+ cacheNames.add(options.name);
65
+ return new cacheWithMetricsProxy.CacheWithMetricsProxy(cache, options, metrics);
66
+ };
67
+ }
42
68
 
43
- exports.cacheFactory = cacheFactory;
69
+ exports.getCacheFactory = getCacheFactory;
@@ -0,0 +1,12 @@
1
+ import { type CacheServerMetricsHandlers } from '@tramvai/tokens-common';
2
+ export declare const cacheMetricsServerProviders: import("@tinkoff/dippy").Provider<{
3
+ metrics: {
4
+ token: import("@tramvai/tokens-metrics").Metrics & {
5
+ __type?: "base token" | undefined;
6
+ };
7
+ optional: boolean;
8
+ };
9
+ }, CacheServerMetricsHandlers & {
10
+ __type?: "base token" | undefined;
11
+ }>[];
12
+ //# sourceMappingURL=cacheMetrics.d.ts.map
@@ -0,0 +1,56 @@
1
+ import { provide, Scope } from '@tinkoff/dippy';
2
+ import { CACHE_METRICS_SERVER_TOKEN } from '@tramvai/tokens-common';
3
+ import { METRICS_MODULE_TOKEN } from '@tramvai/tokens-metrics';
4
+
5
+ const cacheMetricsServerFactory = ({ metrics, }) => {
6
+ const cacheMetrics = metrics
7
+ ? {
8
+ hitCounter: metrics.counter({
9
+ name: 'cache_hit',
10
+ help: 'Successful access to retrieve data from a cache.',
11
+ labelNames: ['name', 'method'],
12
+ }),
13
+ missCounter: metrics.counter({
14
+ name: 'cache_miss',
15
+ help: 'Failed request to retrieve data from a cache.',
16
+ labelNames: ['name', 'method'],
17
+ }),
18
+ cacheMaxGauge: metrics.gauge({
19
+ name: 'cache_max',
20
+ help: 'Maximum number of items in a cache.',
21
+ labelNames: ['name'],
22
+ }),
23
+ cacheSizeGauge: metrics.gauge({
24
+ name: 'cache_size',
25
+ help: 'The total number of items in a cache at the current moment.',
26
+ labelNames: ['name'],
27
+ }),
28
+ }
29
+ : undefined;
30
+ return {
31
+ onHit(name, method) {
32
+ cacheMetrics === null || cacheMetrics === void 0 ? void 0 : cacheMetrics.hitCounter.inc({ name, method });
33
+ },
34
+ onMiss(name, method) {
35
+ cacheMetrics === null || cacheMetrics === void 0 ? void 0 : cacheMetrics.missCounter.inc({ name, method });
36
+ },
37
+ onMax(name, size) {
38
+ cacheMetrics === null || cacheMetrics === void 0 ? void 0 : cacheMetrics.cacheMaxGauge.set({ name }, size);
39
+ },
40
+ onSize(name, size) {
41
+ cacheMetrics === null || cacheMetrics === void 0 ? void 0 : cacheMetrics.cacheSizeGauge.set({ name }, size);
42
+ },
43
+ };
44
+ };
45
+ const cacheMetricsServerProviders = [
46
+ provide({
47
+ provide: CACHE_METRICS_SERVER_TOKEN,
48
+ useFactory: cacheMetricsServerFactory,
49
+ scope: Scope.SINGLETON,
50
+ deps: {
51
+ metrics: { token: METRICS_MODULE_TOKEN, optional: true },
52
+ },
53
+ }),
54
+ ];
55
+
56
+ export { cacheMetricsServerProviders };
@@ -0,0 +1,60 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var dippy = require('@tinkoff/dippy');
6
+ var tokensCommon = require('@tramvai/tokens-common');
7
+ var tokensMetrics = require('@tramvai/tokens-metrics');
8
+
9
+ const cacheMetricsServerFactory = ({ metrics, }) => {
10
+ const cacheMetrics = metrics
11
+ ? {
12
+ hitCounter: metrics.counter({
13
+ name: 'cache_hit',
14
+ help: 'Successful access to retrieve data from a cache.',
15
+ labelNames: ['name', 'method'],
16
+ }),
17
+ missCounter: metrics.counter({
18
+ name: 'cache_miss',
19
+ help: 'Failed request to retrieve data from a cache.',
20
+ labelNames: ['name', 'method'],
21
+ }),
22
+ cacheMaxGauge: metrics.gauge({
23
+ name: 'cache_max',
24
+ help: 'Maximum number of items in a cache.',
25
+ labelNames: ['name'],
26
+ }),
27
+ cacheSizeGauge: metrics.gauge({
28
+ name: 'cache_size',
29
+ help: 'The total number of items in a cache at the current moment.',
30
+ labelNames: ['name'],
31
+ }),
32
+ }
33
+ : undefined;
34
+ return {
35
+ onHit(name, method) {
36
+ cacheMetrics === null || cacheMetrics === void 0 ? void 0 : cacheMetrics.hitCounter.inc({ name, method });
37
+ },
38
+ onMiss(name, method) {
39
+ cacheMetrics === null || cacheMetrics === void 0 ? void 0 : cacheMetrics.missCounter.inc({ name, method });
40
+ },
41
+ onMax(name, size) {
42
+ cacheMetrics === null || cacheMetrics === void 0 ? void 0 : cacheMetrics.cacheMaxGauge.set({ name }, size);
43
+ },
44
+ onSize(name, size) {
45
+ cacheMetrics === null || cacheMetrics === void 0 ? void 0 : cacheMetrics.cacheSizeGauge.set({ name }, size);
46
+ },
47
+ };
48
+ };
49
+ const cacheMetricsServerProviders = [
50
+ dippy.provide({
51
+ provide: tokensCommon.CACHE_METRICS_SERVER_TOKEN,
52
+ useFactory: cacheMetricsServerFactory,
53
+ scope: dippy.Scope.SINGLETON,
54
+ deps: {
55
+ metrics: { token: tokensMetrics.METRICS_MODULE_TOKEN, optional: true },
56
+ },
57
+ }),
58
+ ];
59
+
60
+ exports.cacheMetricsServerProviders = cacheMetricsServerProviders;
@@ -0,0 +1,10 @@
1
+ const CACHE_MAX_DEFAULT = 100;
2
+ function getCacheOptions(cacheType, options) {
3
+ return {
4
+ type: cacheType,
5
+ max: CACHE_MAX_DEFAULT,
6
+ ...options,
7
+ };
8
+ }
9
+
10
+ export { getCacheOptions };
@@ -0,0 +1,3 @@
1
+ import type { CacheFactoryOptions, CacheOptions, CacheType } from '@tramvai/tokens-common';
2
+ export declare function getCacheOptions(cacheType: CacheType, options?: CacheFactoryOptions<typeof cacheType>): CacheOptions<typeof cacheType>;
3
+ //# sourceMappingURL=cacheOptions.d.ts.map
@@ -0,0 +1,10 @@
1
+ const CACHE_MAX_DEFAULT = 100;
2
+ function getCacheOptions(cacheType, options) {
3
+ return {
4
+ type: cacheType,
5
+ max: CACHE_MAX_DEFAULT,
6
+ ...options,
7
+ };
8
+ }
9
+
10
+ export { getCacheOptions };
@@ -0,0 +1,14 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ const CACHE_MAX_DEFAULT = 100;
6
+ function getCacheOptions(cacheType, options) {
7
+ return {
8
+ type: cacheType,
9
+ max: CACHE_MAX_DEFAULT,
10
+ ...options,
11
+ };
12
+ }
13
+
14
+ exports.getCacheOptions = getCacheOptions;
@@ -0,0 +1,14 @@
1
+ import { getCacheOptions } from './cacheOptions.browser.js';
2
+ import { getCacheFactory } from './cacheFactory.browser.browser.js';
3
+
4
+ function cacheRegistry({ caches, cacheNames, metrics, }) {
5
+ return function (cacheType = 'memory', options) {
6
+ const extendedOptions = getCacheOptions(cacheType, options);
7
+ const factory = getCacheFactory();
8
+ const cache = factory(cacheType, extendedOptions);
9
+ caches.push(cache);
10
+ return cache;
11
+ };
12
+ }
13
+
14
+ export { cacheRegistry };
@@ -0,0 +1,7 @@
1
+ import type { Cache, CacheFactory, CacheServerMetricsHandlers } from '@tramvai/tokens-common';
2
+ export declare function cacheRegistry({ caches, cacheNames, metrics, }: {
3
+ caches: Cache[];
4
+ cacheNames: Set<string> | null;
5
+ metrics: CacheServerMetricsHandlers | null;
6
+ }): CacheFactory;
7
+ //# sourceMappingURL=cacheRegistry.d.ts.map
@@ -0,0 +1,14 @@
1
+ import { getCacheOptions } from './cacheOptions.es.js';
2
+ import { getCacheFactory } from './cacheFactory.es.js';
3
+
4
+ function cacheRegistry({ caches, cacheNames, metrics, }) {
5
+ return function (cacheType = 'memory', options) {
6
+ const extendedOptions = getCacheOptions(cacheType, options);
7
+ const factory = getCacheFactory({ cacheNames, metrics });
8
+ const cache = factory(cacheType, extendedOptions);
9
+ caches.push(cache);
10
+ return cache;
11
+ };
12
+ }
13
+
14
+ export { cacheRegistry };
@@ -0,0 +1,18 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var cacheOptions = require('./cacheOptions.js');
6
+ var cacheFactory = require('./cacheFactory.js');
7
+
8
+ function cacheRegistry({ caches, cacheNames, metrics, }) {
9
+ return function (cacheType = 'memory', options) {
10
+ const extendedOptions = cacheOptions.getCacheOptions(cacheType, options);
11
+ const factory = cacheFactory.getCacheFactory({ cacheNames, metrics });
12
+ const cache = factory(cacheType, extendedOptions);
13
+ caches.push(cache);
14
+ return cache;
15
+ };
16
+ }
17
+
18
+ exports.cacheRegistry = cacheRegistry;
@@ -0,0 +1,5 @@
1
+ import type { CacheOptions, CacheType } from '@tramvai/tokens-common';
2
+ import { MEMORY_LRU, MEMORY_LFU } from '@tramvai/tokens-common';
3
+ export declare function isMemoryLRU(options: CacheOptions<CacheType>): options is CacheOptions<typeof MEMORY_LRU>;
4
+ export declare function isMemoryLFU(options: CacheOptions<CacheType>): options is CacheOptions<typeof MEMORY_LFU>;
5
+ //# sourceMappingURL=cacheType.d.ts.map
@@ -0,0 +1,10 @@
1
+ import { MEMORY_LRU, MEMORY_LFU } from '@tramvai/tokens-common';
2
+
3
+ function isMemoryLRU(options) {
4
+ return options.type === MEMORY_LRU;
5
+ }
6
+ function isMemoryLFU(options) {
7
+ return options.type === MEMORY_LFU;
8
+ }
9
+
10
+ export { isMemoryLFU, isMemoryLRU };
@@ -0,0 +1,15 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var tokensCommon = require('@tramvai/tokens-common');
6
+
7
+ function isMemoryLRU(options) {
8
+ return options.type === tokensCommon.MEMORY_LRU;
9
+ }
10
+ function isMemoryLFU(options) {
11
+ return options.type === tokensCommon.MEMORY_LFU;
12
+ }
13
+
14
+ exports.isMemoryLFU = isMemoryLFU;
15
+ exports.isMemoryLRU = isMemoryLRU;
@@ -0,0 +1,25 @@
1
+ import type { Cache, CacheOptions, CacheServerMetricsHandlers, CacheType } from '@tramvai/tokens-common';
2
+ export declare class CacheWithMetricsProxy<T> implements Cache<T> {
3
+ private cache;
4
+ private options;
5
+ private metrics;
6
+ constructor(cache: Cache, options: CacheOptions<CacheType> | undefined, metrics: CacheServerMetricsHandlers | null);
7
+ private handleAccess;
8
+ private syncSize;
9
+ get(key: string): T | undefined;
10
+ peek(key: string): T | undefined;
11
+ has(key: string): boolean;
12
+ set(key: string, value: T, options?: {
13
+ ttl?: number;
14
+ }): void;
15
+ delete(key: string): boolean;
16
+ clear(): void;
17
+ dump(): Array<[string, {
18
+ value: T;
19
+ }]>;
20
+ load(entries: Array<[string, {
21
+ value: T;
22
+ }]>): void;
23
+ get size(): number;
24
+ }
25
+ //# sourceMappingURL=cacheWithMetricsProxy.d.ts.map
@@ -0,0 +1,74 @@
1
+ class CacheWithMetricsProxy {
2
+ constructor(cache, options, metrics) {
3
+ var _a;
4
+ this.cache = cache;
5
+ this.options = options;
6
+ this.metrics = metrics;
7
+ if (this.options &&
8
+ this.options.name &&
9
+ 'max' in this.options &&
10
+ typeof this.options.max === 'number') {
11
+ (_a = this.metrics) === null || _a === void 0 ? void 0 : _a.onMax(this.options.name, this.options.max);
12
+ }
13
+ }
14
+ handleAccess(_key, value, method) {
15
+ var _a, _b, _c;
16
+ if (!((_a = this.options) === null || _a === void 0 ? void 0 : _a.name)) {
17
+ return;
18
+ }
19
+ if (value) {
20
+ (_b = this.metrics) === null || _b === void 0 ? void 0 : _b.onHit(this.options.name, method);
21
+ }
22
+ else {
23
+ (_c = this.metrics) === null || _c === void 0 ? void 0 : _c.onMiss(this.options.name, method);
24
+ }
25
+ }
26
+ syncSize() {
27
+ var _a, _b;
28
+ if (!((_a = this.options) === null || _a === void 0 ? void 0 : _a.name)) {
29
+ return;
30
+ }
31
+ (_b = this.metrics) === null || _b === void 0 ? void 0 : _b.onSize(this.options.name, this.cache.size);
32
+ }
33
+ get(key) {
34
+ const value = this.cache.get(key);
35
+ this.handleAccess(key, value, 'get');
36
+ this.syncSize();
37
+ return value;
38
+ }
39
+ peek(key) {
40
+ const value = this.cache.peek(key);
41
+ this.handleAccess(key, value, 'peek');
42
+ return value;
43
+ }
44
+ has(key) {
45
+ const value = this.cache.has(key);
46
+ this.handleAccess(key, value, 'has');
47
+ return value;
48
+ }
49
+ set(key, value, options) {
50
+ this.cache.set(key, value, options);
51
+ this.syncSize();
52
+ }
53
+ delete(key) {
54
+ const result = this.cache.delete(key);
55
+ this.syncSize();
56
+ return result;
57
+ }
58
+ clear() {
59
+ this.cache.clear();
60
+ this.syncSize();
61
+ }
62
+ dump() {
63
+ return this.cache.dump();
64
+ }
65
+ load(entries) {
66
+ this.cache.load(entries);
67
+ this.syncSize();
68
+ }
69
+ get size() {
70
+ return this.cache.size;
71
+ }
72
+ }
73
+
74
+ export { CacheWithMetricsProxy };
@@ -0,0 +1,78 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ class CacheWithMetricsProxy {
6
+ constructor(cache, options, metrics) {
7
+ var _a;
8
+ this.cache = cache;
9
+ this.options = options;
10
+ this.metrics = metrics;
11
+ if (this.options &&
12
+ this.options.name &&
13
+ 'max' in this.options &&
14
+ typeof this.options.max === 'number') {
15
+ (_a = this.metrics) === null || _a === void 0 ? void 0 : _a.onMax(this.options.name, this.options.max);
16
+ }
17
+ }
18
+ handleAccess(_key, value, method) {
19
+ var _a, _b, _c;
20
+ if (!((_a = this.options) === null || _a === void 0 ? void 0 : _a.name)) {
21
+ return;
22
+ }
23
+ if (value) {
24
+ (_b = this.metrics) === null || _b === void 0 ? void 0 : _b.onHit(this.options.name, method);
25
+ }
26
+ else {
27
+ (_c = this.metrics) === null || _c === void 0 ? void 0 : _c.onMiss(this.options.name, method);
28
+ }
29
+ }
30
+ syncSize() {
31
+ var _a, _b;
32
+ if (!((_a = this.options) === null || _a === void 0 ? void 0 : _a.name)) {
33
+ return;
34
+ }
35
+ (_b = this.metrics) === null || _b === void 0 ? void 0 : _b.onSize(this.options.name, this.cache.size);
36
+ }
37
+ get(key) {
38
+ const value = this.cache.get(key);
39
+ this.handleAccess(key, value, 'get');
40
+ this.syncSize();
41
+ return value;
42
+ }
43
+ peek(key) {
44
+ const value = this.cache.peek(key);
45
+ this.handleAccess(key, value, 'peek');
46
+ return value;
47
+ }
48
+ has(key) {
49
+ const value = this.cache.has(key);
50
+ this.handleAccess(key, value, 'has');
51
+ return value;
52
+ }
53
+ set(key, value, options) {
54
+ this.cache.set(key, value, options);
55
+ this.syncSize();
56
+ }
57
+ delete(key) {
58
+ const result = this.cache.delete(key);
59
+ this.syncSize();
60
+ return result;
61
+ }
62
+ clear() {
63
+ this.cache.clear();
64
+ this.syncSize();
65
+ }
66
+ dump() {
67
+ return this.cache.dump();
68
+ }
69
+ load(entries) {
70
+ this.cache.load(entries);
71
+ this.syncSize();
72
+ }
73
+ get size() {
74
+ return this.cache.size;
75
+ }
76
+ }
77
+
78
+ exports.CacheWithMetricsProxy = CacheWithMetricsProxy;
@@ -1,9 +1,17 @@
1
- import { provide } from '@tramvai/core';
1
+ import { provide, Scope } from '@tramvai/core';
2
2
  import { SERVER_MODULE_PAPI_PRIVATE_ROUTE } from '@tramvai/tokens-server';
3
3
  import { CLEAR_CACHE_TOKEN, LOGGER_TOKEN } from '@tramvai/tokens-common';
4
4
  import { papiClearCache } from './papi.es.js';
5
+ import { CACHE_NAMES_LIST_TOKEN } from './tokens.es.js';
6
+ import { cacheMetricsServerProviders } from './cacheMetrics.es.js';
5
7
 
6
8
  const providers = [
9
+ ...cacheMetricsServerProviders,
10
+ provide({
11
+ provide: CACHE_NAMES_LIST_TOKEN,
12
+ scope: Scope.SINGLETON,
13
+ useValue: new Set(),
14
+ }),
7
15
  provide({
8
16
  provide: SERVER_MODULE_PAPI_PRIVATE_ROUTE,
9
17
  multi: true,
@@ -6,8 +6,16 @@ var core = require('@tramvai/core');
6
6
  var tokensServer = require('@tramvai/tokens-server');
7
7
  var tokensCommon = require('@tramvai/tokens-common');
8
8
  var papi = require('./papi.js');
9
+ var tokens = require('./tokens.js');
10
+ var cacheMetrics = require('./cacheMetrics.js');
9
11
 
10
12
  const providers = [
13
+ ...cacheMetrics.cacheMetricsServerProviders,
14
+ core.provide({
15
+ provide: tokens.CACHE_NAMES_LIST_TOKEN,
16
+ scope: core.Scope.SINGLETON,
17
+ useValue: new Set(),
18
+ }),
11
19
  core.provide({
12
20
  provide: tokensServer.SERVER_MODULE_PAPI_PRIVATE_ROUTE,
13
21
  multi: true,
@@ -0,0 +1,8 @@
1
+ import { createToken } from '@tinkoff/dippy';
2
+
3
+ /** Is used to perform all app caches clearing */
4
+ const CACHES_LIST_TOKEN = createToken('_cachesList');
5
+ /** Is used to check the uniqueness of metrics labels */
6
+ const CACHE_NAMES_LIST_TOKEN = createToken('cache names list');
7
+
8
+ export { CACHES_LIST_TOKEN, CACHE_NAMES_LIST_TOKEN };
@@ -0,0 +1,10 @@
1
+ import type { Cache } from '@tramvai/tokens-common';
2
+ /** Is used to perform all app caches clearing */
3
+ export declare const CACHES_LIST_TOKEN: Cache<any>[] & {
4
+ __type?: "base token" | undefined;
5
+ };
6
+ /** Is used to check the uniqueness of metrics labels */
7
+ export declare const CACHE_NAMES_LIST_TOKEN: Set<string> & {
8
+ __type?: "base token" | undefined;
9
+ };
10
+ //# sourceMappingURL=tokens.d.ts.map
@@ -0,0 +1,8 @@
1
+ import { createToken } from '@tinkoff/dippy';
2
+
3
+ /** Is used to perform all app caches clearing */
4
+ const CACHES_LIST_TOKEN = createToken('_cachesList');
5
+ /** Is used to check the uniqueness of metrics labels */
6
+ const CACHE_NAMES_LIST_TOKEN = createToken('cache names list');
7
+
8
+ export { CACHES_LIST_TOKEN, CACHE_NAMES_LIST_TOKEN };
@@ -0,0 +1,13 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var dippy = require('@tinkoff/dippy');
6
+
7
+ /** Is used to perform all app caches clearing */
8
+ const CACHES_LIST_TOKEN = dippy.createToken('_cachesList');
9
+ /** Is used to check the uniqueness of metrics labels */
10
+ const CACHE_NAMES_LIST_TOKEN = dippy.createToken('cache names list');
11
+
12
+ exports.CACHES_LIST_TOKEN = CACHES_LIST_TOKEN;
13
+ exports.CACHE_NAMES_LIST_TOKEN = CACHE_NAMES_LIST_TOKEN;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tramvai/module-common",
3
- "version": "4.36.2",
3
+ "version": "4.38.0",
4
4
  "description": "",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
@@ -30,36 +30,37 @@
30
30
  "watch": "tsc -w"
31
31
  },
32
32
  "dependencies": {
33
+ "@akashbabu/lfu-cache": "1.0.2",
33
34
  "@tinkoff/errors": "0.5.1",
34
35
  "@tinkoff/hook-runner": "0.6.1",
35
36
  "@tinkoff/lru-cache-nano": "^7.9.0",
36
- "@akashbabu/lfu-cache": "1.0.2",
37
37
  "@tinkoff/pubsub": "0.7.1",
38
38
  "@tinkoff/url": "0.10.1",
39
+ "@tramvai/experiments": "4.38.0",
40
+ "@tramvai/module-cookie": "4.38.0",
41
+ "@tramvai/module-environment": "4.38.0",
42
+ "@tramvai/module-log": "4.38.0",
39
43
  "@tramvai/safe-strings": "0.7.3",
40
- "@tramvai/experiments": "4.36.2",
41
- "@tramvai/module-cookie": "4.36.2",
42
- "@tramvai/module-environment": "4.36.2",
43
- "@tramvai/module-log": "4.36.2",
44
- "@tramvai/tokens-child-app": "4.36.2",
45
- "@tramvai/tokens-core-private": "4.36.2",
46
- "@tramvai/tokens-common": "4.36.2",
47
- "@tramvai/tokens-render": "4.36.2",
48
- "@tramvai/tokens-router": "4.36.2",
49
- "@tramvai/tokens-server-private": "4.36.2",
50
- "@tramvai/types-actions-state-context": "4.36.2",
44
+ "@tramvai/tokens-child-app": "4.38.0",
45
+ "@tramvai/tokens-common": "4.38.0",
46
+ "@tramvai/tokens-core-private": "4.38.0",
47
+ "@tramvai/tokens-metrics": "4.38.0",
48
+ "@tramvai/tokens-render": "4.38.0",
49
+ "@tramvai/tokens-router": "4.38.0",
50
+ "@tramvai/tokens-server-private": "4.38.0",
51
+ "@tramvai/types-actions-state-context": "4.38.0",
51
52
  "hoist-non-react-statics": "^3.3.1",
52
53
  "node-abort-controller": "^3.0.1"
53
54
  },
54
55
  "peerDependencies": {
55
56
  "@tinkoff/dippy": "0.10.8",
56
57
  "@tinkoff/utils": "^2.1.2",
57
- "@tramvai/cli": "4.36.2",
58
- "@tramvai/core": "4.36.2",
59
- "@tramvai/papi": "4.36.2",
60
- "@tramvai/react": "4.36.2",
61
- "@tramvai/state": "4.36.2",
62
- "@tramvai/tokens-server": "4.36.2",
58
+ "@tramvai/cli": "4.38.0",
59
+ "@tramvai/core": "4.38.0",
60
+ "@tramvai/papi": "4.38.0",
61
+ "@tramvai/react": "4.38.0",
62
+ "@tramvai/state": "4.38.0",
63
+ "@tramvai/tokens-server": "4.38.0",
63
64
  "react": ">=16.14.0",
64
65
  "tslib": "^2.4.0"
65
66
  },