@lakutata/cache 3.0.0-beta.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/LICENSE +23 -0
- package/README.md +175 -0
- package/dist/cjs/cache/Cacher.d.ts +446 -0
- package/dist/cjs/cache/Cacher.js +523 -0
- package/dist/cjs/cache/exceptions/CacheDriverNotFoundException.d.ts +10 -0
- package/dist/cjs/cache/exceptions/CacheDriverNotFoundException.js +17 -0
- package/dist/cjs/cache/interfaces/CacherOptions.d.ts +42 -0
- package/dist/cjs/cache/interfaces/CacherOptions.js +2 -0
- package/dist/cjs/cache/lib/LikePrefix.d.ts +5 -0
- package/dist/cjs/cache/lib/LikePrefix.js +10 -0
- package/dist/cjs/cache/lib/LoadDriver.d.ts +6 -0
- package/dist/cjs/cache/lib/LoadDriver.js +66 -0
- package/dist/cjs/cache/lib/Serializer.d.ts +18 -0
- package/dist/cjs/cache/lib/Serializer.js +46 -0
- package/dist/cjs/cache/lib/WithTimeout.d.ts +7 -0
- package/dist/cjs/cache/lib/WithTimeout.js +23 -0
- package/dist/cjs/cache/options/FileCacheOptions.d.ts +54 -0
- package/dist/cjs/cache/options/FileCacheOptions.js +62 -0
- package/dist/cjs/cache/options/MemcacheCacheOptions.d.ts +57 -0
- package/dist/cjs/cache/options/MemcacheCacheOptions.js +66 -0
- package/dist/cjs/cache/options/MemoryCacheOptions.d.ts +39 -0
- package/dist/cjs/cache/options/MemoryCacheOptions.js +52 -0
- package/dist/cjs/cache/options/MongoCacheOptions.d.ts +72 -0
- package/dist/cjs/cache/options/MongoCacheOptions.js +81 -0
- package/dist/cjs/cache/options/MysqlCacheOptions.d.ts +73 -0
- package/dist/cjs/cache/options/MysqlCacheOptions.js +82 -0
- package/dist/cjs/cache/options/PostgresCacheOptions.d.ts +87 -0
- package/dist/cjs/cache/options/PostgresCacheOptions.js +92 -0
- package/dist/cjs/cache/options/RedisCacheOptions.d.ts +120 -0
- package/dist/cjs/cache/options/RedisCacheOptions.js +113 -0
- package/dist/cjs/cache/options/SqliteCacheOptions.d.ts +53 -0
- package/dist/cjs/cache/options/SqliteCacheOptions.js +61 -0
- package/dist/cjs/cache/stores/CacheStore.d.ts +44 -0
- package/dist/cjs/cache/stores/CacheStore.js +42 -0
- package/dist/cjs/cache/stores/CreateCacheStore.d.ts +7 -0
- package/dist/cjs/cache/stores/CreateCacheStore.js +37 -0
- package/dist/cjs/cache/stores/FileStore.d.ts +51 -0
- package/dist/cjs/cache/stores/FileStore.js +143 -0
- package/dist/cjs/cache/stores/MemcacheStore.d.ts +42 -0
- package/dist/cjs/cache/stores/MemcacheStore.js +69 -0
- package/dist/cjs/cache/stores/MemoryStore.d.ts +34 -0
- package/dist/cjs/cache/stores/MemoryStore.js +75 -0
- package/dist/cjs/cache/stores/MongoStore.d.ts +55 -0
- package/dist/cjs/cache/stores/MongoStore.js +72 -0
- package/dist/cjs/cache/stores/MysqlStore.d.ts +27 -0
- package/dist/cjs/cache/stores/MysqlStore.js +71 -0
- package/dist/cjs/cache/stores/PostgresStore.d.ts +30 -0
- package/dist/cjs/cache/stores/PostgresStore.js +85 -0
- package/dist/cjs/cache/stores/RedisStore.d.ts +58 -0
- package/dist/cjs/cache/stores/RedisStore.js +131 -0
- package/dist/cjs/cache/stores/SerializedCacheStore.d.ts +48 -0
- package/dist/cjs/cache/stores/SerializedCacheStore.js +80 -0
- package/dist/cjs/cache/stores/SqliteStore.d.ts +44 -0
- package/dist/cjs/cache/stores/SqliteStore.js +91 -0
- package/dist/cjs/cache/types/CacheStoreOptions.d.ts +15 -0
- package/dist/cjs/cache/types/CacheStoreOptions.js +2 -0
- package/dist/cjs/exports/Cache.d.ts +12 -0
- package/dist/cjs/exports/Cache.js +31 -0
- package/dist/cjs/package.json +1 -0
- package/dist/esm/cache/Cacher.js +518 -0
- package/dist/esm/cache/exceptions/CacheDriverNotFoundException.js +13 -0
- package/dist/esm/cache/interfaces/CacherOptions.js +1 -0
- package/dist/esm/cache/lib/LikePrefix.js +7 -0
- package/dist/esm/cache/lib/LoadDriver.js +30 -0
- package/dist/esm/cache/lib/Serializer.js +42 -0
- package/dist/esm/cache/lib/WithTimeout.js +20 -0
- package/dist/esm/cache/options/FileCacheOptions.js +58 -0
- package/dist/esm/cache/options/MemcacheCacheOptions.js +62 -0
- package/dist/esm/cache/options/MemoryCacheOptions.js +48 -0
- package/dist/esm/cache/options/MongoCacheOptions.js +77 -0
- package/dist/esm/cache/options/MysqlCacheOptions.js +78 -0
- package/dist/esm/cache/options/PostgresCacheOptions.js +88 -0
- package/dist/esm/cache/options/RedisCacheOptions.js +109 -0
- package/dist/esm/cache/options/SqliteCacheOptions.js +57 -0
- package/dist/esm/cache/stores/CacheStore.js +36 -0
- package/dist/esm/cache/stores/CreateCacheStore.js +34 -0
- package/dist/esm/cache/stores/FileStore.js +136 -0
- package/dist/esm/cache/stores/MemcacheStore.js +65 -0
- package/dist/esm/cache/stores/MemoryStore.js +71 -0
- package/dist/esm/cache/stores/MongoStore.js +68 -0
- package/dist/esm/cache/stores/MysqlStore.js +67 -0
- package/dist/esm/cache/stores/PostgresStore.js +81 -0
- package/dist/esm/cache/stores/RedisStore.js +127 -0
- package/dist/esm/cache/stores/SerializedCacheStore.js +76 -0
- package/dist/esm/cache/stores/SqliteStore.js +87 -0
- package/dist/esm/cache/types/CacheStoreOptions.js +1 -0
- package/dist/esm/exports/Cache.js +12 -0
- package/dist/types/cache/Cacher.d.ts +446 -0
- package/dist/types/cache/exceptions/CacheDriverNotFoundException.d.ts +10 -0
- package/dist/types/cache/interfaces/CacherOptions.d.ts +42 -0
- package/dist/types/cache/lib/LikePrefix.d.ts +5 -0
- package/dist/types/cache/lib/LoadDriver.d.ts +6 -0
- package/dist/types/cache/lib/Serializer.d.ts +18 -0
- package/dist/types/cache/lib/WithTimeout.d.ts +7 -0
- package/dist/types/cache/options/FileCacheOptions.d.ts +54 -0
- package/dist/types/cache/options/MemcacheCacheOptions.d.ts +57 -0
- package/dist/types/cache/options/MemoryCacheOptions.d.ts +39 -0
- package/dist/types/cache/options/MongoCacheOptions.d.ts +72 -0
- package/dist/types/cache/options/MysqlCacheOptions.d.ts +73 -0
- package/dist/types/cache/options/PostgresCacheOptions.d.ts +87 -0
- package/dist/types/cache/options/RedisCacheOptions.d.ts +120 -0
- package/dist/types/cache/options/SqliteCacheOptions.d.ts +53 -0
- package/dist/types/cache/stores/CacheStore.d.ts +44 -0
- package/dist/types/cache/stores/CreateCacheStore.d.ts +7 -0
- package/dist/types/cache/stores/FileStore.d.ts +51 -0
- package/dist/types/cache/stores/MemcacheStore.d.ts +42 -0
- package/dist/types/cache/stores/MemoryStore.d.ts +34 -0
- package/dist/types/cache/stores/MongoStore.d.ts +55 -0
- package/dist/types/cache/stores/MysqlStore.d.ts +27 -0
- package/dist/types/cache/stores/PostgresStore.d.ts +30 -0
- package/dist/types/cache/stores/RedisStore.d.ts +58 -0
- package/dist/types/cache/stores/SerializedCacheStore.d.ts +48 -0
- package/dist/types/cache/stores/SqliteStore.d.ts +44 -0
- package/dist/types/cache/types/CacheStoreOptions.d.ts +15 -0
- package/dist/types/exports/Cache.d.ts +12 -0
- package/package.json +72 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023-present Lakutata
|
|
4
|
+
|
|
5
|
+
All rights reserved
|
|
6
|
+
|
|
7
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
9
|
+
in the Software without restriction, including without limitation the rights
|
|
10
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
11
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
12
|
+
furnished to do so, subject to the following conditions:
|
|
13
|
+
|
|
14
|
+
The above copyright notice and this permission notice shall be included in all
|
|
15
|
+
copies or substantial portions of the Software.
|
|
16
|
+
|
|
17
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
20
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
21
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
22
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
23
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
# @lakutata/cache
|
|
2
|
+
|
|
3
|
+
The cache component of the lakutata framework: a key-value cache with expiration (TTLs in milliseconds), the
|
|
4
|
+
cache-aside `wrap()` with its background refresh, and events, backed by one or more stores: memory, a JSON file,
|
|
5
|
+
Redis, Memcache, MongoDB, SQLite, PostgreSQL or MySQL. Several stores make tiers, the fastest first. The umbrella
|
|
6
|
+
package `lakutata` re-exports it as `lakutata/com/cacher`.
|
|
7
|
+
|
|
8
|
+
## Installation
|
|
9
|
+
|
|
10
|
+
```shell
|
|
11
|
+
npm install lakutata
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
The memory and file stores need nothing more; the other stores use optional peer dependencies, installed when used.
|
|
15
|
+
A store whose package is missing fails the cache's creation with `CacheDriverNotFoundException`.
|
|
16
|
+
|
|
17
|
+
| Store | `type` | Install |
|
|
18
|
+
|---|---|---|
|
|
19
|
+
| Memory (also the store of a cache without `stores`) | `'memory'` | none |
|
|
20
|
+
| JSON file | `'file'` | none |
|
|
21
|
+
| Redis 4+ (or Valkey) | `'redis'` | `redis` (4 or 5) |
|
|
22
|
+
| Memcache | `'memcache'` | `memjs` |
|
|
23
|
+
| MongoDB | `'mongo'` | `mongodb` |
|
|
24
|
+
| SQLite | `'sqlite'` | `sqlite3` |
|
|
25
|
+
| PostgreSQL | `'postgres'` | `pg` |
|
|
26
|
+
| MySQL / MariaDB | `'mysql'` | `mysql2` |
|
|
27
|
+
|
|
28
|
+
## Usage
|
|
29
|
+
|
|
30
|
+
### A cache in an application
|
|
31
|
+
|
|
32
|
+
Register the `Cacher` component with `buildCacherOptions`, then get it with `getObject()` or `@Inject`. Without
|
|
33
|
+
`stores`, it caches in memory.
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
import {Application} from 'lakutata'
|
|
37
|
+
import {buildCacherOptions, type Cacher} from 'lakutata/com/cacher'
|
|
38
|
+
|
|
39
|
+
Application
|
|
40
|
+
.run(() => ({
|
|
41
|
+
id: 'cache.app',
|
|
42
|
+
name: 'Cache',
|
|
43
|
+
components: {
|
|
44
|
+
//Entries expire after 10 minutes unless a write gives another TTL
|
|
45
|
+
cache: buildCacherOptions({ttl: 600000})
|
|
46
|
+
}
|
|
47
|
+
}))
|
|
48
|
+
.onLaunched(async (app: Application): Promise<void> => {
|
|
49
|
+
const cache: Cacher = await app.getObject('cache')
|
|
50
|
+
await cache.set('user:1', {id: 1, name: 'Ada'})
|
|
51
|
+
//A TTL of its own (30 seconds); 0 never expires
|
|
52
|
+
await cache.set('session:abc', 'token', 30000)
|
|
53
|
+
console.log(await cache.get<{id: number, name: string}>('user:1'))
|
|
54
|
+
//undefined: a missing or expired key
|
|
55
|
+
console.log(await cache.get('user:2'))
|
|
56
|
+
await cache.multipleSet([{key: 'a', value: 1}, {key: 'b', value: 2, ttl: 5000}])
|
|
57
|
+
console.log(await cache.multipleGet(['a', 'b', 'c'])) //[1, 2, undefined]
|
|
58
|
+
await cache.del('session:abc')
|
|
59
|
+
await cache.clear()
|
|
60
|
+
})
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Cache-aside with `wrap()`
|
|
64
|
+
|
|
65
|
+
`wrap()` returns the cached value, or computes it, caches it and returns it. The concurrent calls on one key share one
|
|
66
|
+
computation. With a refresh threshold, a value close to its expiration is returned at once and recomputed in the
|
|
67
|
+
background.
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
import {Component} from 'lakutata'
|
|
71
|
+
import {Inject} from 'lakutata/decorator/di'
|
|
72
|
+
import type {Cacher} from 'lakutata/com/cacher'
|
|
73
|
+
|
|
74
|
+
type Weather = {city: string, celsius: number}
|
|
75
|
+
|
|
76
|
+
class WeatherService extends Component {
|
|
77
|
+
@Inject('cache')
|
|
78
|
+
protected readonly cache: Cacher
|
|
79
|
+
|
|
80
|
+
public async weather(city: string): Promise<Weather> {
|
|
81
|
+
//Fetched at most every 10 minutes; in the last 2 minutes, served while fetched again in the background
|
|
82
|
+
return this.cache.wrap(`weather:${city}`, (): Promise<Weather> => this.fetch(city), {
|
|
83
|
+
ttl: 600000,
|
|
84
|
+
refreshThreshold: 120000
|
|
85
|
+
})
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
protected async fetch(city: string): Promise<Weather> {
|
|
89
|
+
return {city: city, celsius: 21}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Stores and tiers
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
import {Application} from 'lakutata'
|
|
98
|
+
import {buildCacherOptions} from 'lakutata/com/cacher'
|
|
99
|
+
|
|
100
|
+
Application.run(() => ({
|
|
101
|
+
id: 'tiers.app',
|
|
102
|
+
name: 'Tiers',
|
|
103
|
+
components: {
|
|
104
|
+
cache: buildCacherOptions({
|
|
105
|
+
//Read from the first store holding the key; written to and deleted from both
|
|
106
|
+
stores: [
|
|
107
|
+
{type: 'file', filename: './cache/local.json'},
|
|
108
|
+
{type: 'redis', host: '127.0.0.1', namespace: 'tiers'}
|
|
109
|
+
],
|
|
110
|
+
ttl: 300000
|
|
111
|
+
})
|
|
112
|
+
}
|
|
113
|
+
}))
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
- A read returns the entry of the first store holding it; only `wrap()` copies an entry found in a lower store to
|
|
117
|
+
the stores above it.
|
|
118
|
+
- A store failing to read is a miss; its error is emitted as an `'error'` event. A store failing to write or delete
|
|
119
|
+
rejects the call, unless `nonBlocking: true` (the calls then return without waiting for the stores).
|
|
120
|
+
- A store which cannot connect when the cache starts fails its creation, and so the application's start (a Redis
|
|
121
|
+
store with `throwOnConnectError: false` keeps trying in the background instead).
|
|
122
|
+
- The memory store keeps the values by reference. The other stores keep them as JSON: a `Buffer` is kept, a `Date`
|
|
123
|
+
comes back as its ISO string, a class instance as a plain object.
|
|
124
|
+
- `namespace` separates the applications sharing a backend: `clear()` then deletes the namespace's entries only
|
|
125
|
+
(except Memcache, whose `clear()` flushes the whole server).
|
|
126
|
+
|
|
127
|
+
### Events
|
|
128
|
+
|
|
129
|
+
```typescript
|
|
130
|
+
import type {Cacher, OnRefreshEventData, OnSetEventData} from 'lakutata/com/cacher'
|
|
131
|
+
|
|
132
|
+
declare const cache: Cacher
|
|
133
|
+
|
|
134
|
+
cache.on('set', (data: OnSetEventData): void => {
|
|
135
|
+
if (data.error) console.error(`Writing ${data.key} failed`, data.error)
|
|
136
|
+
})
|
|
137
|
+
cache.on('refresh', (data: OnRefreshEventData): void => {
|
|
138
|
+
if (data.error) console.warn(`Refreshing ${data.key} failed, the cached value is kept`)
|
|
139
|
+
})
|
|
140
|
+
//The errors no call reports: failed reads (misses), lost connections, failed file saves
|
|
141
|
+
cache.on('error', (error: Error): void => console.error('Cache store error', error))
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## API
|
|
145
|
+
|
|
146
|
+
| Export | What it is |
|
|
147
|
+
|---|---|
|
|
148
|
+
| `Cacher` | The component: `set`, `get`, `multipleSet`, `multipleGet`, `getTTL`, `wrap`, `del`, `multipleDel`, `clear`, the events `set`, `del`, `clear`, `refresh`, `error` |
|
|
149
|
+
| `buildCacherOptions` | Builds the component options of a `Cacher` |
|
|
150
|
+
| `CacherOptions` | The options: `stores`, `ttl`, `refreshThreshold`, `refreshAllStores`, `nonBlocking` |
|
|
151
|
+
| `CacheStoreOptions` | The options of one store, told apart by `type` |
|
|
152
|
+
| `MemoryCacheOptions`, `FileCacheOptions`, `RedisCacheOptions`, `MemcacheCacheOptions`, `MongoCacheOptions`, `SqliteCacheOptions`, `PostgresCacheOptions`, `MysqlCacheOptions` | The options of each store |
|
|
153
|
+
| `WrapOptions` | The TTL and refresh threshold of a `wrap()` call |
|
|
154
|
+
| `MultipleSetInput` | An entry of `multipleSet()` |
|
|
155
|
+
| `OnSetEventData`, `OnDeleteEventData`, `OnRefreshEventData` | The data of the `set`, `del` and `refresh` events |
|
|
156
|
+
| `CacheDriverNotFoundException` | A store's driver package is not installed |
|
|
157
|
+
|
|
158
|
+
All are exported by `lakutata/com/cacher` and `@lakutata/cache`. The typings document each declaration with examples.
|
|
159
|
+
|
|
160
|
+
## Errors
|
|
161
|
+
|
|
162
|
+
| Exception | Thrown when |
|
|
163
|
+
|---|---|
|
|
164
|
+
| `CacheDriverNotFoundException` (`E_CACHE_DRIVER_NOT_FOUND`) | The cache starts with a store whose driver package (`redis`, `memjs`, `mongodb`, `sqlite3`, `pg`, `mysql2`) is not installed |
|
|
165
|
+
| `InvalidValueException` (from `lakutata`) | The cache options are invalid, when the component is created |
|
|
166
|
+
|
|
167
|
+
The failures of the stores (a refused connection, a failed query) are their drivers' errors: they fail the cache's
|
|
168
|
+
creation when it connects, reject the writes and deletions (without `nonBlocking`), and are emitted as `'error'`
|
|
169
|
+
events for the reads.
|
|
170
|
+
|
|
171
|
+
## See also
|
|
172
|
+
|
|
173
|
+
- `@lakutata/core` (`lakutata`): the components, `Application` and the dependency injection (`doc/en/Core.md` of the
|
|
174
|
+
package `lakutata`, Chinese in `doc/zh`).
|
|
175
|
+
- `@lakutata/mutex` (`lakutata/com/mutex`): the locks, to compute a cached value in one instance at a time.
|
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
import { CacherOptions } from './interfaces/CacherOptions.js';
|
|
2
|
+
import { Component, ComponentOptionsBuilder } from '@lakutata/core';
|
|
3
|
+
import { CacheStoreOptions } from './types/CacheStoreOptions.js';
|
|
4
|
+
import { CacheStore } from './stores/CacheStore.js';
|
|
5
|
+
import { CacheEntry } from './lib/Serializer.js';
|
|
6
|
+
/**
|
|
7
|
+
* Build the component options of a {@link Cacher}, to register it in the `components` of an application (or a module)
|
|
8
|
+
* under the name of your choice. The options are validated when the component is created, not here.
|
|
9
|
+
* @param options The cache options: its stores, its default TTL, its refresh and write behavior. Without options, one
|
|
10
|
+
* in-memory store whose entries never expire.
|
|
11
|
+
* @returns The component options (`{class: Cacher, ...options}`).
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* import {Application} from 'lakutata'
|
|
15
|
+
* import {buildCacherOptions, type Cacher} from 'lakutata/com/cacher'
|
|
16
|
+
*
|
|
17
|
+
* Application
|
|
18
|
+
* .run(() => ({
|
|
19
|
+
* id: 'cache.app',
|
|
20
|
+
* name: 'Cache',
|
|
21
|
+
* components: {
|
|
22
|
+
* //An in-memory cache whose entries expire after one minute
|
|
23
|
+
* cache: buildCacherOptions({ttl: 60000})
|
|
24
|
+
* }
|
|
25
|
+
* }))
|
|
26
|
+
* .onLaunched(async (app: Application): Promise<void> => {
|
|
27
|
+
* const cache: Cacher = await app.getObject('cache')
|
|
28
|
+
* await cache.set('greeting', 'Hello')
|
|
29
|
+
* console.log(await cache.get<string>('greeting')) //Hello
|
|
30
|
+
* })
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export declare const buildCacherOptions: ComponentOptionsBuilder<CacherOptions>;
|
|
34
|
+
/**
|
|
35
|
+
* An entry written by {@link Cacher.multipleSet}.
|
|
36
|
+
*/
|
|
37
|
+
export type MultipleSetInput = {
|
|
38
|
+
/**
|
|
39
|
+
* The key of the entry.
|
|
40
|
+
*/
|
|
41
|
+
key: string;
|
|
42
|
+
/**
|
|
43
|
+
* The value to cache. The stores other than the memory one keep it as JSON (see {@link Cacher}).
|
|
44
|
+
*/
|
|
45
|
+
value: any;
|
|
46
|
+
/**
|
|
47
|
+
* The entry's time to live, in milliseconds; `0` never expires.
|
|
48
|
+
* @default the cache's `ttl` option (never expires without it)
|
|
49
|
+
*/
|
|
50
|
+
ttl?: number;
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* The data of a `'set'` event of a {@link Cacher}.
|
|
54
|
+
*/
|
|
55
|
+
export type OnSetEventData = {
|
|
56
|
+
/**
|
|
57
|
+
* The key written.
|
|
58
|
+
*/
|
|
59
|
+
key: string;
|
|
60
|
+
/**
|
|
61
|
+
* The value written.
|
|
62
|
+
*/
|
|
63
|
+
value: any;
|
|
64
|
+
/**
|
|
65
|
+
* The error of the write when it failed; absent when it succeeded.
|
|
66
|
+
*/
|
|
67
|
+
error?: Error;
|
|
68
|
+
};
|
|
69
|
+
/**
|
|
70
|
+
* The data of a `'del'` event of a {@link Cacher}.
|
|
71
|
+
*/
|
|
72
|
+
export type OnDeleteEventData = {
|
|
73
|
+
/**
|
|
74
|
+
* The key deleted.
|
|
75
|
+
*/
|
|
76
|
+
key: string;
|
|
77
|
+
/**
|
|
78
|
+
* The error of the deletion when it failed; absent when it succeeded.
|
|
79
|
+
*/
|
|
80
|
+
error?: Error;
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* The data of a `'refresh'` event of a {@link Cacher}: a value recomputed in the background by
|
|
84
|
+
* {@link Cacher.wrap}.
|
|
85
|
+
*/
|
|
86
|
+
export type OnRefreshEventData = {
|
|
87
|
+
/**
|
|
88
|
+
* The key refreshed.
|
|
89
|
+
*/
|
|
90
|
+
key: string;
|
|
91
|
+
/**
|
|
92
|
+
* The new value; the value still cached when the refresh failed.
|
|
93
|
+
*/
|
|
94
|
+
value: any;
|
|
95
|
+
/**
|
|
96
|
+
* The error thrown by the computation or by a store when the refresh failed; absent when it succeeded.
|
|
97
|
+
*/
|
|
98
|
+
error?: Error;
|
|
99
|
+
};
|
|
100
|
+
/**
|
|
101
|
+
* The options of {@link Cacher.wrap}.
|
|
102
|
+
*/
|
|
103
|
+
export type WrapOptions<T = any> = {
|
|
104
|
+
/**
|
|
105
|
+
* The time to live of the computed value, in milliseconds (`0` never expires), or a function of the value returning
|
|
106
|
+
* it.
|
|
107
|
+
* @default the cache's `ttl` option (never expires without it)
|
|
108
|
+
*/
|
|
109
|
+
ttl?: number | ((value: T) => number);
|
|
110
|
+
/**
|
|
111
|
+
* When a cached value has less time to live than this, in milliseconds, `wrap()` returns it and recomputes it in
|
|
112
|
+
* the background; or a function of the cached value returning it. Ignored for the entries which never expire.
|
|
113
|
+
* @default the cache's `refreshThreshold` option (no background refresh without it)
|
|
114
|
+
*/
|
|
115
|
+
refreshThreshold?: number | ((value: T) => number);
|
|
116
|
+
};
|
|
117
|
+
type StoreHit = {
|
|
118
|
+
entry: CacheEntry;
|
|
119
|
+
index: number;
|
|
120
|
+
};
|
|
121
|
+
/**
|
|
122
|
+
* The cache component: a key-value cache with expiration, backed by one or more stores (memory, file, Redis,
|
|
123
|
+
* Memcache, MongoDB, SQLite, PostgreSQL, MySQL). Register it in the `components` of an application with
|
|
124
|
+
* {@link buildCacherOptions} (or `{class: Cacher, ...options}`) and get it with `getObject()` or `@Inject`; it is a
|
|
125
|
+
* singleton. Without stores, it caches in memory.
|
|
126
|
+
*
|
|
127
|
+
* The stores connect when the component is created: when one fails to connect, the others are disconnected and the
|
|
128
|
+
* creation fails with its error (the application does not start). A store whose driver package is not installed
|
|
129
|
+
* fails with {@link CacheDriverNotFoundException}. The stores disconnect when the component is destroyed, after the
|
|
130
|
+
* background refreshes in progress and the file store's pending writes.
|
|
131
|
+
*
|
|
132
|
+
* With several stores, they are tiers, the first one the fastest: a read returns the entry of the first store holding
|
|
133
|
+
* it, a write or a deletion goes to all of them. Only {@link Cacher.wrap} copies an entry found in a lower store to
|
|
134
|
+
* the stores above it.
|
|
135
|
+
*
|
|
136
|
+
* The TTLs are in milliseconds: an entry whose TTL is `0` or unset (without the `ttl` option) never expires; an expired
|
|
137
|
+
* entry is a miss. The memory store keeps the values by reference (a cached object changed afterwards is changed in the
|
|
138
|
+
* cache); the other stores keep them as JSON: the `Buffer`s are kept, but a `Date` comes back as its ISO string, a
|
|
139
|
+
* class instance as a plain object, a `Map` or a `Set` as `{}`, and a `bigint` fails the write.
|
|
140
|
+
*
|
|
141
|
+
* A store failing to read is a miss (its error is emitted as an `'error'` event); a store failing to write or delete
|
|
142
|
+
* rejects the call, unless the `nonBlocking` option is set.
|
|
143
|
+
* @example
|
|
144
|
+
* ```typescript
|
|
145
|
+
* import {Application, Component} from 'lakutata'
|
|
146
|
+
* import {Inject} from 'lakutata/decorator/di'
|
|
147
|
+
* import {buildCacherOptions, type Cacher} from 'lakutata/com/cacher'
|
|
148
|
+
*
|
|
149
|
+
* type Product = {id: number, name: string}
|
|
150
|
+
*
|
|
151
|
+
* class Catalog extends Component {
|
|
152
|
+
* @Inject('cache')
|
|
153
|
+
* protected readonly cache: Cacher
|
|
154
|
+
*
|
|
155
|
+
* public async product(id: number): Promise<Product> {
|
|
156
|
+
* //Computed once, then read from the cache for 5 minutes (recomputed in the background in its last minute)
|
|
157
|
+
* return this.cache.wrap(`product:${id}`, async (): Promise<Product> => ({id: id, name: `Product ${id}`}), {
|
|
158
|
+
* ttl: 300000,
|
|
159
|
+
* refreshThreshold: 60000
|
|
160
|
+
* })
|
|
161
|
+
* }
|
|
162
|
+
*
|
|
163
|
+
* public async rename(id: number, name: string): Promise<void> {
|
|
164
|
+
* await this.cache.set(`product:${id}`, {id: id, name: name}, 300000)
|
|
165
|
+
* }
|
|
166
|
+
*
|
|
167
|
+
* public async remove(id: number): Promise<void> {
|
|
168
|
+
* await this.cache.del(`product:${id}`)
|
|
169
|
+
* }
|
|
170
|
+
* }
|
|
171
|
+
*
|
|
172
|
+
* Application
|
|
173
|
+
* .run(() => ({
|
|
174
|
+
* id: 'catalog.app',
|
|
175
|
+
* name: 'Catalog',
|
|
176
|
+
* components: {
|
|
177
|
+
* //A local file tier in front of Redis (the "redis" package installed)
|
|
178
|
+
* cache: buildCacherOptions({
|
|
179
|
+
* stores: [
|
|
180
|
+
* {type: 'file', filename: './cache/catalog.json'},
|
|
181
|
+
* {type: 'redis', host: '127.0.0.1', namespace: 'catalog'}
|
|
182
|
+
* ],
|
|
183
|
+
* ttl: 600000
|
|
184
|
+
* }),
|
|
185
|
+
* catalog: {class: Catalog}
|
|
186
|
+
* }
|
|
187
|
+
* }))
|
|
188
|
+
* .onLaunched(async (app: Application): Promise<void> => {
|
|
189
|
+
* const cache: Cacher = await app.getObject('cache')
|
|
190
|
+
* cache.on('error', (error: Error): void => console.error('Cache store error', error))
|
|
191
|
+
* const catalog: Catalog = await app.getObject('catalog')
|
|
192
|
+
* console.log(await catalog.product(1))
|
|
193
|
+
* })
|
|
194
|
+
* ```
|
|
195
|
+
*/
|
|
196
|
+
export declare class Cacher extends Component {
|
|
197
|
+
#private;
|
|
198
|
+
/**
|
|
199
|
+
* The stores, the fastest first: the options of one store or an array of them (`type` chooses the store).
|
|
200
|
+
* @default one in-memory store
|
|
201
|
+
*/
|
|
202
|
+
protected readonly stores?: CacheStoreOptions[] | CacheStoreOptions;
|
|
203
|
+
/**
|
|
204
|
+
* The default time to live of the entries, in milliseconds (a positive integer), used when a write gives none.
|
|
205
|
+
* @default none: the entries never expire
|
|
206
|
+
*/
|
|
207
|
+
protected readonly ttl?: number;
|
|
208
|
+
/**
|
|
209
|
+
* The default refresh threshold of {@link Cacher.wrap}, in milliseconds (a positive integer): a cached value with
|
|
210
|
+
* less time to live is recomputed in the background.
|
|
211
|
+
* @default none: no background refresh
|
|
212
|
+
*/
|
|
213
|
+
protected readonly refreshThreshold?: number;
|
|
214
|
+
/**
|
|
215
|
+
* Whether a background refresh writes the new value to all the stores, instead of the store holding the value and
|
|
216
|
+
* the stores above it.
|
|
217
|
+
* @default false
|
|
218
|
+
*/
|
|
219
|
+
protected readonly refreshAllStores?: boolean;
|
|
220
|
+
/**
|
|
221
|
+
* Whether the writes and the deletions return without waiting for the stores (their failures emitted as events,
|
|
222
|
+
* the calls never rejecting), and, with several stores, the reads query them all at once and return the first
|
|
223
|
+
* entry found (not necessarily the first store's).
|
|
224
|
+
* @default false
|
|
225
|
+
*/
|
|
226
|
+
protected readonly nonBlocking?: boolean;
|
|
227
|
+
/**
|
|
228
|
+
* An identifier of the cache. It is accepted for compatibility and not used.
|
|
229
|
+
*/
|
|
230
|
+
protected readonly cacheId?: string;
|
|
231
|
+
protected init(): Promise<void>;
|
|
232
|
+
protected destroy(): Promise<void>;
|
|
233
|
+
/**
|
|
234
|
+
* Emit a store error as an `'error'` event; dropped when the event has no listener.
|
|
235
|
+
* @param error The error.
|
|
236
|
+
* @protected
|
|
237
|
+
*/
|
|
238
|
+
protected report(error: unknown): void;
|
|
239
|
+
/**
|
|
240
|
+
* Resolve the time to live of a value.
|
|
241
|
+
* @param ttl The TTL in milliseconds, a function of the value returning it, or undefined for the cache's `ttl`
|
|
242
|
+
* option.
|
|
243
|
+
* @param value The value cached.
|
|
244
|
+
* @returns The TTL in milliseconds, undefined when the entry never expires.
|
|
245
|
+
* @protected
|
|
246
|
+
*/
|
|
247
|
+
protected resolveTTL<T>(ttl: number | ((value: T) => number) | undefined, value: T): number | undefined;
|
|
248
|
+
/**
|
|
249
|
+
* Read an entry from one store; a failing store is a miss, its error emitted as an `'error'` event.
|
|
250
|
+
* @param store The store.
|
|
251
|
+
* @param key The key.
|
|
252
|
+
* @returns The entry, undefined when it is missing, expired or the store failed.
|
|
253
|
+
* @protected
|
|
254
|
+
*/
|
|
255
|
+
protected readStore(store: CacheStore, key: string): Promise<CacheEntry | undefined>;
|
|
256
|
+
/**
|
|
257
|
+
* Read an entry from the first store holding it, in the stores' order; with `nonBlocking` and several stores, from
|
|
258
|
+
* the first store answering with it.
|
|
259
|
+
* @param key The key.
|
|
260
|
+
* @returns The entry and the index of its store, undefined on a miss.
|
|
261
|
+
* @protected
|
|
262
|
+
*/
|
|
263
|
+
protected read(key: string): Promise<StoreHit | undefined>;
|
|
264
|
+
/**
|
|
265
|
+
* Run an operation on stores, in parallel. With `nonBlocking`, it resolves at once and a failure is only passed to
|
|
266
|
+
* `onError`.
|
|
267
|
+
* @param stores The stores.
|
|
268
|
+
* @param operation The operation run on each store.
|
|
269
|
+
* @param onError Called with the first failure.
|
|
270
|
+
* @throws {Error} The first failure of the operation, without `nonBlocking`.
|
|
271
|
+
* @protected
|
|
272
|
+
*/
|
|
273
|
+
protected runOnStores(stores: CacheStore[], operation: (store: CacheStore) => Promise<unknown>, onError: (error: Error) => void): Promise<void>;
|
|
274
|
+
/**
|
|
275
|
+
* Cache a value under a key, in all the stores, replacing the previous one. A `'set'` event is emitted once
|
|
276
|
+
* written; when a store fails, a `'set'` event carrying the error is emitted and the call rejects.
|
|
277
|
+
*
|
|
278
|
+
* With `nonBlocking`, the call resolves and the `'set'` event is emitted before the stores are written; a failure
|
|
279
|
+
* then emits a second `'set'` event carrying the error.
|
|
280
|
+
* @param key The key.
|
|
281
|
+
* @param value The value. The stores other than the memory one keep it as JSON.
|
|
282
|
+
* @param ttl The time to live, in milliseconds; `0` never expires. Defaults to the cache's `ttl` option (never
|
|
283
|
+
* expires without it).
|
|
284
|
+
* @returns The value given.
|
|
285
|
+
* @throws {Error} The failure of a store (its driver's error, or a `TypeError` for a value JSON cannot write),
|
|
286
|
+
* without `nonBlocking`.
|
|
287
|
+
*/
|
|
288
|
+
set<T>(key: string, value: T, ttl?: number): Promise<T>;
|
|
289
|
+
/**
|
|
290
|
+
* Cache several values, in all the stores (in one batch per store where the store allows it). No `'set'` event is
|
|
291
|
+
* emitted; a failure is emitted as an `'error'` event and rejects the call (unless `nonBlocking`).
|
|
292
|
+
* @param options The entries; an entry without `ttl` gets the cache's `ttl` option.
|
|
293
|
+
* @returns The entries written, their TTL resolved.
|
|
294
|
+
* @throws {Error} The failure of a store, without `nonBlocking`.
|
|
295
|
+
*/
|
|
296
|
+
multipleSet(options: MultipleSetInput[]): Promise<MultipleSetInput[]>;
|
|
297
|
+
/**
|
|
298
|
+
* Read the value of a key, from the first store holding it. It does not copy the value to the stores above (see
|
|
299
|
+
* {@link Cacher.wrap}). A failing store is a miss (its error emitted as an `'error'` event): it never rejects.
|
|
300
|
+
* @param key The key.
|
|
301
|
+
* @returns The value; undefined when the key is missing or expired (or when undefined was cached).
|
|
302
|
+
*/
|
|
303
|
+
get<T = any>(key: string): Promise<T>;
|
|
304
|
+
/**
|
|
305
|
+
* Read the values of several keys; each key from the first store holding it (the missing keys only are asked to
|
|
306
|
+
* the next store). A failing store misses all its keys (its error emitted as an `'error'` event): it never rejects.
|
|
307
|
+
* @param keys The keys.
|
|
308
|
+
* @returns The values, in the order of the keys: undefined for the missing and expired ones.
|
|
309
|
+
*/
|
|
310
|
+
multipleGet(keys: string[]): Promise<any[]>;
|
|
311
|
+
/**
|
|
312
|
+
* Read when a key expires. Despite its name, it returns a point in time, not a remaining duration: compute the
|
|
313
|
+
* time left with `expires - Date.now()`.
|
|
314
|
+
* @param key The key.
|
|
315
|
+
* @returns The expiration time, in milliseconds since the epoch; `-1` when the key is missing, expired or never
|
|
316
|
+
* expires.
|
|
317
|
+
*/
|
|
318
|
+
getTTL(key: string): Promise<number>;
|
|
319
|
+
/**
|
|
320
|
+
* Read the value of a key, or compute it and cache it when it is missing or expired (the cache-aside pattern).
|
|
321
|
+
*
|
|
322
|
+
* - The concurrent calls on the same key share one call and its result, whatever their `fn` and options.
|
|
323
|
+
* - A value found in a lower store is copied to the stores above it, with the time it has left (or the `ttl` of
|
|
324
|
+
* the call when it never expires).
|
|
325
|
+
* - With a refresh threshold, a cached value with less time to live than the threshold is returned at once and
|
|
326
|
+
* recomputed in the background (one refresh per key at a time), then written to its store and the stores above
|
|
327
|
+
* (to all the stores with `refreshAllStores`); a `'refresh'` event reports the new value or the failure, the
|
|
328
|
+
* cached value kept then. A threshold higher than the TTL refreshes the value on each call.
|
|
329
|
+
* - A computed value is written with {@link Cacher.set} (a `'set'` event); `undefined` is cached too.
|
|
330
|
+
* @param key The key.
|
|
331
|
+
* @param fn Computes the value when it is missing; its failure rejects the call and nothing is cached.
|
|
332
|
+
* @param options The time to live in milliseconds (`0` never expires), or the TTL and the refresh threshold.
|
|
333
|
+
* Default to the cache's `ttl` and `refreshThreshold` options.
|
|
334
|
+
* @returns The cached or computed value.
|
|
335
|
+
* @throws {Error} The error thrown by `fn`, or the failure of a store writing the computed value (without
|
|
336
|
+
* `nonBlocking`).
|
|
337
|
+
* @example
|
|
338
|
+
* ```typescript
|
|
339
|
+
* import type {Cacher} from 'lakutata/com/cacher'
|
|
340
|
+
*
|
|
341
|
+
* declare const cache: Cacher
|
|
342
|
+
* declare function loadRates(): Promise<Record<string, number>>
|
|
343
|
+
*
|
|
344
|
+
* //Loaded at most once per hour; in its last 5 minutes, served while reloaded in the background
|
|
345
|
+
* const rates: Record<string, number> = await cache.wrap('rates', loadRates, {ttl: 3600000, refreshThreshold: 300000})
|
|
346
|
+
* //A TTL depending on the value
|
|
347
|
+
* const user: {id: number, guest: boolean} = await cache.wrap('user:1', async () => ({id: 1, guest: true}), {
|
|
348
|
+
* ttl: (value: {id: number, guest: boolean}): number => value.guest ? 60000 : 3600000
|
|
349
|
+
* })
|
|
350
|
+
* ```
|
|
351
|
+
*/
|
|
352
|
+
wrap<T>(key: string, fn: () => T | Promise<T>, options?: number | WrapOptions<T>): Promise<T>;
|
|
353
|
+
/**
|
|
354
|
+
* Run one {@link Cacher.wrap} call: read the key, compute and write it on a miss, copy it to the stores above or
|
|
355
|
+
* start its background refresh on a hit.
|
|
356
|
+
* @param key The key.
|
|
357
|
+
* @param fn Computes the value.
|
|
358
|
+
* @param options The TTL and the refresh threshold.
|
|
359
|
+
* @returns The cached or computed value.
|
|
360
|
+
* @throws {Error} The error thrown by `fn`, or the failure of a store writing the computed value.
|
|
361
|
+
* @protected
|
|
362
|
+
*/
|
|
363
|
+
protected computeWrap<T>(key: string, fn: () => T | Promise<T>, options: WrapOptions<T>): Promise<T>;
|
|
364
|
+
/**
|
|
365
|
+
* Recompute a value in the background, unless the key is being refreshed already, and emit a `'refresh'` event
|
|
366
|
+
* with the new value or the failure. The component's destruction waits for it.
|
|
367
|
+
* @param key The key.
|
|
368
|
+
* @param fn Computes the value.
|
|
369
|
+
* @param options The TTL of the new value.
|
|
370
|
+
* @param current The value cached, reported by the event when the refresh fails.
|
|
371
|
+
* @param index The index of the store holding the value: the new value is written to it and to the stores above
|
|
372
|
+
* (to all the stores with `refreshAllStores`).
|
|
373
|
+
* @protected
|
|
374
|
+
*/
|
|
375
|
+
protected refresh<T>(key: string, fn: () => T | Promise<T>, options: WrapOptions<T>, current: T, index: number): void;
|
|
376
|
+
/**
|
|
377
|
+
* Delete a key from all the stores. A `'del'` event is emitted once deleted; when a store fails, a `'del'` event
|
|
378
|
+
* carrying the error is emitted and the call rejects. With `nonBlocking`, it resolves and emits the `'del'` event
|
|
379
|
+
* before the stores are done, a failure emitting a second `'del'` event carrying the error.
|
|
380
|
+
* @param key The key; a missing key is not an error.
|
|
381
|
+
* @returns Always true, whether the key existed or not.
|
|
382
|
+
* @throws {Error} The failure of a store, without `nonBlocking`.
|
|
383
|
+
*/
|
|
384
|
+
del(key: string): Promise<boolean>;
|
|
385
|
+
/**
|
|
386
|
+
* Delete several keys from all the stores. No `'del'` event is emitted; a failure is emitted as an `'error'` event
|
|
387
|
+
* and rejects the call (unless `nonBlocking`).
|
|
388
|
+
* @param keys The keys; the missing ones are not an error.
|
|
389
|
+
* @returns Always true, whether the keys existed or not.
|
|
390
|
+
* @throws {Error} The failure of a store, without `nonBlocking`.
|
|
391
|
+
*/
|
|
392
|
+
multipleDel(keys: string[]): Promise<boolean>;
|
|
393
|
+
/**
|
|
394
|
+
* Delete all the entries of each store: the entries of its namespace when it has one, otherwise all its entries
|
|
395
|
+
* (except, in Redis, the keys containing the `keyPrefixSeparator`, which belong to the namespaces). A Memcache
|
|
396
|
+
* store flushes the whole server, its namespace ignored. A `'clear'` event is emitted once done; when a store fails,
|
|
397
|
+
* a `'clear'` event carrying the error is emitted and the call rejects (unless `nonBlocking`, which resolves and
|
|
398
|
+
* emits the event at once).
|
|
399
|
+
* @returns Always true.
|
|
400
|
+
* @throws {Error} The failure of a store, without `nonBlocking`.
|
|
401
|
+
*/
|
|
402
|
+
clear(): Promise<boolean>;
|
|
403
|
+
/**
|
|
404
|
+
* Listen to the writes of {@link Cacher.set} and {@link Cacher.wrap}, successful or failed (`data.error`). The
|
|
405
|
+
* listener is called asynchronously, after the emitting.
|
|
406
|
+
* @param event `'set'`.
|
|
407
|
+
* @param listener Called with the key, the value and the error of a failed write.
|
|
408
|
+
* @returns The component, for chaining.
|
|
409
|
+
*/
|
|
410
|
+
on(event: 'set', listener: (data: OnSetEventData) => void): this;
|
|
411
|
+
/**
|
|
412
|
+
* Listen to the deletions of {@link Cacher.del}, successful or failed (`data.error`). The listener is called
|
|
413
|
+
* asynchronously, after the emitting.
|
|
414
|
+
* @param event `'del'`.
|
|
415
|
+
* @param listener Called with the key and the error of a failed deletion.
|
|
416
|
+
* @returns The component, for chaining.
|
|
417
|
+
*/
|
|
418
|
+
on(event: 'del', listener: (data: OnDeleteEventData) => void): this;
|
|
419
|
+
/**
|
|
420
|
+
* Listen to the clearings of {@link Cacher.clear}, successful or failed. The listener is called asynchronously,
|
|
421
|
+
* after the emitting.
|
|
422
|
+
* @param event `'clear'`.
|
|
423
|
+
* @param listener Called without argument on a success, with the error on a failure.
|
|
424
|
+
* @returns The component, for chaining.
|
|
425
|
+
*/
|
|
426
|
+
on(event: 'clear', listener: (error?: Error) => void): this;
|
|
427
|
+
/**
|
|
428
|
+
* Listen to the background refreshes of {@link Cacher.wrap}, successful or failed (`data.error`). The listener is
|
|
429
|
+
* called asynchronously, after the emitting.
|
|
430
|
+
* @param event `'refresh'`.
|
|
431
|
+
* @param listener Called with the key, the new value (the cached one on a failure) and the error of a failure.
|
|
432
|
+
* @returns The component, for chaining.
|
|
433
|
+
*/
|
|
434
|
+
on(event: 'refresh', listener: (data: OnRefreshEventData) => void): this;
|
|
435
|
+
/**
|
|
436
|
+
* Listen to the store errors which reject no call: the failed reads (counted as misses), the failures of
|
|
437
|
+
* {@link Cacher.multipleSet} and {@link Cacher.multipleDel}, of the copies to the upper stores, and the errors of
|
|
438
|
+
* the connections (a lost Redis connection, a failed file write…). Without listener, these errors are dropped.
|
|
439
|
+
* The listener is called asynchronously, after the emitting.
|
|
440
|
+
* @param event `'error'`.
|
|
441
|
+
* @param listener Called with the error.
|
|
442
|
+
* @returns The component, for chaining.
|
|
443
|
+
*/
|
|
444
|
+
on(event: 'error', listener: (error: Error) => void): this;
|
|
445
|
+
}
|
|
446
|
+
export {};
|