@fluojs/redis 1.0.2 → 1.1.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.ko.md CHANGED
@@ -32,7 +32,7 @@ npm install @fluojs/redis ioredis
32
32
 
33
33
  `RedisModule.forRoot(options)`는 기본 Redis 클라이언트와 `RedisService` 파사드를 등록하는 지원되는 root entrypoint입니다.
34
34
 
35
- `RedisModule.forRoot(...)`는 의도적으로 동기 방식입니다. NestJS의 `forRootAsync(...)` 같은 async dynamic module에서 마이그레이션할 때는 secret, 환경별 host, 외부에서 만든 client를 애플리케이션 경계에서 먼저 해석한 뒤 최종 Redis 옵션을 `forRoot(...)`에 전달하세요. fluo는 Redis module wiring을 module graph 안의 숨겨진 async factory로 미루지 않습니다.
35
+ `RedisModule.forRoot(...)`는 의도적으로 동기 방식이며 Redis constructor option으로 항상 새 `ioredis` client를 생성합니다. 외부에서 만든 client를 채택하지 않습니다. NestJS의 `forRootAsync(...)` 같은 async dynamic module에서 마이그레이션할 때는 secret, 환경별 host, TLS option을 애플리케이션 경계에서 먼저 해석한 뒤 최종 Redis option을 `forRoot(...)`에 전달하세요. 외부에서 만든 client는 이 module 밖에 두고 애플리케이션 lifecycle에서 닫아야 합니다. fluo는 Redis module wiring을 module graph 안의 숨겨진 async factory로 미루지 않습니다.
36
36
 
37
37
  ```typescript
38
38
  import { Module } from '@fluojs/core';
@@ -53,7 +53,7 @@ export class AppModule {}
53
53
 
54
54
  `RedisService`를 주입받아 고수준 작업을 수행하거나, `REDIS_CLIENT`를 통해 원시 `ioredis` 인스턴스를 직접 사용할 수 있습니다.
55
55
 
56
- `RedisService.get()`은 JSON parse를 시도하고 실패하면 raw string을 반환합니다. 누락된 key는 `null`을 반환합니다. `RedisService.set()`은 값을 `JSON.stringify()`로 직렬화하고 양수 TTL에만 `EX`를 사용합니다.
56
+ `RedisService.get()`은 JSON parse를 시도하고 실패하면 raw string을 반환합니다. 누락된 key는 `null`을 반환합니다. `RedisService.set()`은 값을 `JSON.stringify()`로 직렬화하며, 유한한 양의 정수 TTL에는 Redis `EX`를 사용하고 유한한 양의 소수 TTL에는 올림한 밀리초 값으로 `PX`를 사용합니다. TTL을 생략하거나 0 이하 또는 유한하지 않은 값을 전달하면 persistent key를 저장합니다.
57
57
 
58
58
  ```typescript
59
59
  import { Inject } from '@fluojs/core';
@@ -77,12 +77,12 @@ export class CacheRepository {
77
77
 
78
78
  ### 수명 주기 소유권
79
79
 
80
- `@fluojs/redis`는 `RedisModule.forRoot({ name, ... })`로 등록한 이름 있는 연결을 포함해, 자신이 생성한 모든 Redis 클라이언트의 수명 주기를 직접 관리합니다.
80
+ `RedisModule.forRoot(...)` 등록은 각각 새 client를 생성하며, `@fluojs/redis`는 `RedisModule.forRoot({ name, ... })`로 등록한 이름 있는 연결을 포함해 client의 lifecycle을 직접 관리합니다. module은 기존 client instance를 채택하지 않습니다.
81
81
 
82
82
  - 호출자가 옵션을 강제로 캐스팅하더라도 Fluo는 항상 `lazyConnect: true`를 강제하므로, 소켓은 import 시점이 아니라 애플리케이션 bootstrap 중에 열립니다.
83
83
  - bootstrap 단계에서는 클라이언트가 ioredis `wait` 상태일 때만 lifecycle service가 `connect()`를 호출합니다.
84
84
  - lifecycle이 소유한 `connect()`와 `quit()` 호출은 package timeout(기본 `10_000` ms)으로 제한되어, Redis 명령이 멈춰도 bootstrap/shutdown이 무기한 대기하지 않습니다. `lifecycle.connectTimeoutMs`와 `lifecycle.quitTimeoutMs`로 재정의할 수 있으며, host process가 의도적으로 무제한 대기를 소유하는 경우에만 `0`을 전달하세요.
85
- - shutdown 단계에서는 ready/connecting 계열 상태에 `quit()`를 우선 시도해 정상 종료를 노리고, wait/종료 전이 상태에서는 `disconnect()`를 직접 사용합니다.
85
+ - shutdown 단계에서는 ready/connecting 계열 상태에 `quit()`를 우선 시도해 정상 종료를 노리고, monitoring, wait/종료 전이 상태에서는 `disconnect()`를 직접 사용합니다.
86
86
  - `quit()`가 실패하면 Fluo는 `disconnect()`로 fallback하고, 그 뒤에도 클라이언트가 닫히지 않은 경우에만 에러를 다시 던집니다.
87
87
 
88
88
  ### 이름 있는 클라이언트
@@ -91,6 +91,7 @@ export class CacheRepository {
91
91
 
92
92
  - `name`을 생략하면 기본 별칭인 `REDIS_CLIENT` / `RedisService`를 사용합니다.
93
93
  - `name`을 지정하면 `getRedisClientToken(name)` / `getRedisServiceToken(name)`으로 이름 있는 바인딩을 가져옵니다.
94
+ - `name`은 Fluo 등록만 식별합니다. ioredis Sentinel master name은 `sentinelName`으로 전달하세요. Fluo는 등록 토큰을 바꾸지 않고 이를 ioredis 생성자 `name` 옵션으로 전달합니다.
94
95
  - 이름 있는 클라이언트도 기본 클라이언트와 동일한 bootstrap/shutdown 계약을 따르며, `REDIS_CLIENT` / `RedisService` 별칭은 기본 등록에서만 export됩니다.
95
96
  - 이름은 trim되며, blank 또는 whitespace-only name은 token/component helper에서 거부됩니다.
96
97
 
@@ -111,6 +112,7 @@ const ANALYTICS_REDIS_CLIENT = getRedisClientToken('analytics');
111
112
  imports: [
112
113
  RedisModule.forRoot({ host: 'localhost', port: 6379 }),
113
114
  RedisModule.forRoot({ name: 'analytics', host: 'localhost', port: 6380 }),
115
+ RedisModule.forRoot({ name: 'sentinel-cache', sentinelName: 'mymaster', sentinels: [{ host: 'localhost', port: 26379 }] }),
114
116
  ],
115
117
  })
116
118
  export class AppModule {}
@@ -200,7 +202,7 @@ export class PubSubTransportFactory {
200
202
  ### 타입
201
203
  - `DefaultRedisModuleOptions`: 이름 없는 기본 Redis 등록이 받는 옵션입니다. 선택적 global alias visibility와 lifecycle timeout control을 포함합니다.
202
204
  - `NamedRedisModuleOptions`: 추가 이름 있는 Redis 등록이 받는 옵션입니다. 필수 `name`과 scoped lifecycle timeout control을 포함합니다.
203
- - `RedisModuleOptions`: Fluo가 module-only `name`, `global`, `lifecycle` 필드를 제거한 뒤 `ioredis` 생성자에 전달하는 설정 옵션입니다.
205
+ - `RedisModuleOptions`: Fluo가 module-only `name`, `global`, `lifecycle`, `sentinelName` 필드를 제거한 뒤 `ioredis` 생성자에 전달하는 설정 옵션입니다. `sentinelName`은 ioredis Sentinel master `name`으로 전달되고, `name`은 Fluo 등록 식별자로 유지됩니다.
204
206
  - `RedisClientOptions`: Fluo가 module-only field를 제거하고 내부에서 `lazyConnect: true`를 강제하기 전의 Redis constructor option입니다.
205
207
  - `RedisLifecycleOptions`: Fluo가 소유한 `connect()`와 `quit()` lifecycle command의 timeout을 조정하는 선택적 옵션입니다.
206
208
  - `PersistencePlatformStatusSnapshot`, `RedisStatusAdapterInput`: status snapshot input/output type입니다.
package/README.md CHANGED
@@ -32,7 +32,7 @@ npm install @fluojs/redis ioredis
32
32
 
33
33
  Use `RedisModule.forRoot(options)` to register the default Redis client and `RedisService` facade.
34
34
 
35
- `RedisModule.forRoot(...)` is intentionally synchronous. When migrating from NestJS async dynamic modules such as `forRootAsync(...)`, resolve secrets, environment-specific hosts, or externally constructed clients at the application boundary first, then pass the final Redis options into `forRoot(...)`. fluo does not defer Redis module wiring to an async factory hidden inside the module graph.
35
+ `RedisModule.forRoot(...)` is intentionally synchronous and always creates a new `ioredis` client from Redis constructor options; it does not adopt an externally constructed client. When migrating from NestJS async dynamic modules such as `forRootAsync(...)`, resolve secrets, environment-specific hosts, and TLS options at the application boundary first, then pass the final Redis options into `forRoot(...)`. Keep externally constructed clients outside this module and close them from the application lifecycle. fluo does not defer Redis module wiring to an async factory hidden inside the module graph.
36
36
 
37
37
  ```typescript
38
38
  import { Module } from '@fluojs/core';
@@ -53,7 +53,7 @@ export class AppModule {}
53
53
 
54
54
  Inject `RedisService` for high-level operations or `REDIS_CLIENT` for the raw `ioredis` instance.
55
55
 
56
- `RedisService.get()` attempts JSON parsing and falls back to the raw string; missing keys return `null`. `RedisService.set()` serializes values with `JSON.stringify()` and uses `EX` only for positive TTL values.
56
+ `RedisService.get()` attempts JSON parsing and falls back to the raw string; missing keys return `null`. `RedisService.set()` serializes values with `JSON.stringify()`: finite positive integer TTLs use Redis `EX`, while finite positive fractional TTLs use `PX` with milliseconds rounded up. Omit the TTL or pass a non-positive or non-finite value for a persistent key.
57
57
 
58
58
  ```typescript
59
59
  import { Inject } from '@fluojs/core';
@@ -77,12 +77,12 @@ export class CacheRepository {
77
77
 
78
78
  ### Lifecycle Ownership
79
79
 
80
- `@fluojs/redis` owns the lifecycle of every client it creates, including named clients registered through `RedisModule.forRoot({ name, ... })`.
80
+ Every `RedisModule.forRoot(...)` registration creates a new client that `@fluojs/redis` owns, including named clients registered through `RedisModule.forRoot({ name, ... })`. The module never adopts an existing client instance.
81
81
 
82
82
  - Fluo always forces `lazyConnect: true`, even if callers cast options manually, so sockets open during application bootstrap instead of import time.
83
83
  - During bootstrap, the lifecycle service only calls `connect()` while the client is still in ioredis `wait` state.
84
84
  - Lifecycle-owned `connect()` and `quit()` calls are bounded by package timeouts (`10_000` ms by default) so bootstrap and shutdown do not wait forever on a stalled Redis command. Override them with `lifecycle.connectTimeoutMs` and `lifecycle.quitTimeoutMs`; pass `0` only when the host process intentionally owns an unbounded wait.
85
- - During shutdown, ready/connecting clients attempt `quit()` first for graceful teardown, while wait/closed-transition states use `disconnect()` directly.
85
+ - During shutdown, ready/connecting clients attempt `quit()` first for graceful teardown, while monitoring, wait, and closed-transition states use `disconnect()` directly.
86
86
  - If `quit()` fails, Fluo falls back to `disconnect()` and only rethrows when the client still remains open afterward.
87
87
 
88
88
  ### Named Clients
@@ -91,6 +91,7 @@ Use `RedisModule.forRoot({ name, ...options })` when one application needs more
91
91
 
92
92
  - Omit `name` when you want the default aliases: `REDIS_CLIENT` / `RedisService`.
93
93
  - Pass `name` when you want the named helpers: `getRedisClientToken(name)` / `getRedisServiceToken(name)`.
94
+ - `name` identifies the Fluo registration only. For an ioredis Sentinel master name, pass `sentinelName`; Fluo forwards it to ioredis as its constructor `name` option without changing the registration tokens.
94
95
  - Named clients follow the same bootstrap/shutdown contract as the default client; only the default registration exports the `REDIS_CLIENT` / `RedisService` aliases.
95
96
  - Names are trimmed, and blank or whitespace-only names are rejected by token/component helpers.
96
97
 
@@ -111,6 +112,7 @@ const ANALYTICS_REDIS_CLIENT = getRedisClientToken('analytics');
111
112
  imports: [
112
113
  RedisModule.forRoot({ host: 'localhost', port: 6379 }),
113
114
  RedisModule.forRoot({ name: 'analytics', host: 'localhost', port: 6380 }),
115
+ RedisModule.forRoot({ name: 'sentinel-cache', sentinelName: 'mymaster', sentinels: [{ host: 'localhost', port: 26379 }] }),
114
116
  ],
115
117
  })
116
118
  export class AppModule {}
@@ -200,7 +202,7 @@ export class PubSubTransportFactory {
200
202
  ### Types
201
203
  - `DefaultRedisModuleOptions`: Options accepted by the unnamed default Redis registration, including optional global alias visibility and lifecycle timeout controls.
202
204
  - `NamedRedisModuleOptions`: Options accepted by additional named Redis registrations, including required `name` and scoped lifecycle timeout controls.
203
- - `RedisModuleOptions`: Configuration options passed to the `ioredis` constructor after Fluo removes module-only `name`, `global`, and `lifecycle` fields.
205
+ - `RedisModuleOptions`: Configuration options passed to the `ioredis` constructor after Fluo removes module-only `name`, `global`, `lifecycle`, and `sentinelName` fields. `sentinelName` is forwarded as the ioredis Sentinel master `name`, while `name` remains the Fluo registration identifier.
204
206
  - `RedisClientOptions`: Redis constructor options after Fluo removes module-only fields and before it forces `lazyConnect: true` internally.
205
207
  - `RedisLifecycleOptions`: Optional timeout controls for Fluo-owned `connect()` and `quit()` lifecycle commands.
206
208
  - `PersistencePlatformStatusSnapshot`, `RedisStatusAdapterInput`: Status snapshot input/output types.
@@ -1 +1 @@
1
- {"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../src/module.ts"],"names":[],"mappings":"AACA,OAAO,EAAgB,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAMhE,OAAO,KAAK,EAA6C,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAoIhG,yEAAyE;AACzE,qBAAa,WAAW;IACtB;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,kBAAkB,GAAG,UAAU;CAYxD"}
1
+ {"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../src/module.ts"],"names":[],"mappings":"AACA,OAAO,EAAgB,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAMhE,OAAO,KAAK,EAA6C,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAuIhG,yEAAyE;AACzE,qBAAa,WAAW;IACtB;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,kBAAkB,GAAG,UAAU;CAYxD"}
package/dist/module.js CHANGED
@@ -26,6 +26,7 @@ function normalizeRedisModuleOptions(options) {
26
26
  global,
27
27
  lifecycle,
28
28
  name,
29
+ sentinelName,
29
30
  ...clientOptions
30
31
  } = options;
31
32
  const normalizedName = name?.trim();
@@ -37,7 +38,12 @@ function normalizeRedisModuleOptions(options) {
37
38
  throw new Error('Named Redis registrations are scoped and cannot be registered globally.');
38
39
  }
39
40
  return {
40
- clientOptions,
41
+ clientOptions: {
42
+ ...clientOptions,
43
+ ...(sentinelName === undefined ? {} : {
44
+ name: sentinelName
45
+ })
46
+ },
41
47
  global: normalizedName === undefined ? global ?? true : false,
42
48
  lifecycleOptions,
43
49
  name: normalizedName
@@ -38,7 +38,7 @@ export declare class RedisService {
38
38
  *
39
39
  * @param key Redis key to write.
40
40
  * @param value Serializable value stored as JSON.
41
- * @param ttlSeconds Optional TTL in seconds. Omit or pass a non-positive value for a persistent key.
41
+ * @param ttlSeconds Optional TTL in seconds. Finite positive integers use `EX`; finite positive fractions use `PX` rounded up to milliseconds. Omit or pass a non-positive or non-finite value for a persistent key.
42
42
  * @returns A promise that resolves after Redis acknowledges the write.
43
43
  */
44
44
  set<T>(key: string, value: T, ttlSeconds?: number): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"redis-service.d.ts","sourceRoot":"","sources":["../src/redis-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,KAAK,KAAK,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,KAAK,KAAK,MAAM,SAAS,CAAC;AA0BjC;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBACa,YAAY;IACX,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,KAAK;IAE1C;;;;;OAKG;IACG,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,MAAM,GAAG,IAAI,CAAC;IASrD;;;;;;;OAOG;IACG,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IASvE;;;;;OAKG;IACG,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIrC;;;;OAIG;IACH,YAAY,IAAI,KAAK;CAGtB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC,YAAY,CAAC,CAMvE"}
1
+ {"version":3,"file":"redis-service.d.ts","sourceRoot":"","sources":["../src/redis-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,KAAK,KAAK,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,KAAK,KAAK,MAAM,SAAS,CAAC;AA0BjC;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBACa,YAAY;IACX,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,KAAK;IAE1C;;;;;OAKG;IACG,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,MAAM,GAAG,IAAI,CAAC;IASrD;;;;;;;OAOG;IACG,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAevE;;;;;OAKG;IACG,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIrC;;;;OAIG;IACH,YAAY,IAAI,KAAK;CAGtB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC,YAAY,CAAC,CAMvE"}
@@ -75,16 +75,20 @@ class RedisService {
75
75
  *
76
76
  * @param key Redis key to write.
77
77
  * @param value Serializable value stored as JSON.
78
- * @param ttlSeconds Optional TTL in seconds. Omit or pass a non-positive value for a persistent key.
78
+ * @param ttlSeconds Optional TTL in seconds. Finite positive integers use `EX`; finite positive fractions use `PX` rounded up to milliseconds. Omit or pass a non-positive or non-finite value for a persistent key.
79
79
  * @returns A promise that resolves after Redis acknowledges the write.
80
80
  */
81
81
  async set(key, value, ttlSeconds) {
82
82
  const serialized = JSON.stringify(value);
83
- if (ttlSeconds !== undefined && ttlSeconds > 0) {
84
- await this.client.set(key, serialized, 'EX', ttlSeconds);
85
- } else {
86
- await this.client.set(key, serialized);
83
+ if (ttlSeconds !== undefined && Number.isFinite(ttlSeconds) && ttlSeconds > 0) {
84
+ if (Number.isInteger(ttlSeconds)) {
85
+ await this.client.set(key, serialized, 'EX', ttlSeconds);
86
+ return;
87
+ }
88
+ await this.client.set(key, serialized, 'PX', Math.ceil(ttlSeconds * 1000));
89
+ return;
87
90
  }
91
+ await this.client.set(key, serialized);
88
92
  }
89
93
 
90
94
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,SAAS,CAAC;AACjC,OAAO,KAAK,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAI3E,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAqDxD;;GAEG;AACH,qBACa,qBAAsB,YAAW,YAAY,EAAE,qBAAqB;IAE7E,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC;IAC5B,OAAO,CAAC,QAAQ,CAAC,gBAAgB;gBAFhB,MAAM,EAAE,KAAK,EACb,UAAU,CAAC,EAAE,MAAM,YAAA,EACnB,gBAAgB,GAAE,qBAA0B;IAGzD,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ7B,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC;IAgB5C,4BAA4B;IAO5B,OAAO,CAAC,mBAAmB;IAI3B,OAAO,CAAC,oBAAoB;YAMd,0BAA0B;YAiB1B,6BAA6B;IAc3C,OAAO,CAAC,cAAc;CAGvB"}
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,SAAS,CAAC;AACjC,OAAO,KAAK,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAI3E,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAqDxD;;GAEG;AACH,qBACa,qBAAsB,YAAW,YAAY,EAAE,qBAAqB;IAE7E,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC;IAC5B,OAAO,CAAC,QAAQ,CAAC,gBAAgB;gBAFhB,MAAM,EAAE,KAAK,EACb,UAAU,CAAC,EAAE,MAAM,YAAA,EACnB,gBAAgB,GAAE,qBAA0B;IAGzD,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ7B,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC;IAgB5C,4BAA4B;IAO5B,OAAO,CAAC,mBAAmB;IAI3B,OAAO,CAAC,oBAAoB;YAMd,0BAA0B;YAiB1B,6BAA6B;IAsB3C,OAAO,CAAC,cAAc;CAGvB"}
package/dist/service.js CHANGED
@@ -8,7 +8,7 @@ import { Inject } from '@fluojs/core';
8
8
  import { createRedisPlatformStatusSnapshot } from './status.js';
9
9
  import { getRedisComponentId, REDIS_CLIENT } from './tokens.js';
10
10
  const QUITTABLE_STATUSES = new Set(['connect', 'connecting', 'ready', 'reconnecting']);
11
- const DISCONNECTABLE_STATUSES = new Set(['close', 'connect', 'connecting', 'ready', 'reconnecting', 'wait']);
11
+ const DISCONNECTABLE_STATUSES = new Set(['close', 'connect', 'connecting', 'monitoring', 'ready', 'reconnecting', 'wait']);
12
12
  const DEFAULT_REDIS_LIFECYCLE_TIMEOUT_MS = 10_000;
13
13
  function isClosed(status) {
14
14
  return status === 'end';
@@ -102,10 +102,14 @@ class RedisLifecycleService {
102
102
  }
103
103
  }
104
104
  async connectWithDisconnectFallback() {
105
+ const connectPromise = this.client.connect();
105
106
  try {
106
- await withLifecycleTimeout(this.client.connect(), normalizeTimeoutMs(this.lifecycleOptions.connectTimeoutMs), `Redis client ${this.describeClient()} connect timed out after ${String(normalizeTimeoutMs(this.lifecycleOptions.connectTimeoutMs))}ms.`);
107
+ await withLifecycleTimeout(connectPromise, normalizeTimeoutMs(this.lifecycleOptions.connectTimeoutMs), `Redis client ${this.describeClient()} connect timed out after ${String(normalizeTimeoutMs(this.lifecycleOptions.connectTimeoutMs))}ms.`);
107
108
  } catch (error) {
108
109
  this.disconnectIfPossible(this.client.status);
110
+ void connectPromise.then(() => {
111
+ this.disconnectIfPossible(this.client.status);
112
+ }, () => undefined);
109
113
  throw error;
110
114
  }
111
115
  }
package/dist/types.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { RedisOptions } from 'ioredis';
2
- type RedisConnectionOptions = Omit<RedisOptions, 'lazyConnect'>;
2
+ type RedisConnectionOptions = Omit<RedisOptions, 'lazyConnect' | 'name'>;
3
3
  /** Lifecycle timeout controls for Redis connections owned by Fluo. */
4
4
  export interface RedisLifecycleOptions {
5
5
  /** Maximum finite non-negative time to wait for bootstrap `connect()` before failing startup. Defaults to `10_000`; `0` disables the timeout. */
@@ -14,6 +14,8 @@ export type DefaultRedisModuleOptions = RedisConnectionOptions & {
14
14
  /** Timeout controls for lifecycle-owned `connect()` and `quit()` calls. */
15
15
  lifecycle?: RedisLifecycleOptions;
16
16
  name?: undefined;
17
+ /** ioredis Sentinel master name forwarded as the Redis constructor `name` option. */
18
+ sentinelName?: string;
17
19
  };
18
20
  /** Options accepted by an additional named Redis registration. */
19
21
  export type NamedRedisModuleOptions = RedisConnectionOptions & {
@@ -21,6 +23,8 @@ export type NamedRedisModuleOptions = RedisConnectionOptions & {
21
23
  lifecycle?: RedisLifecycleOptions;
22
24
  /** Registration name used to derive named raw-client and facade tokens. */
23
25
  name: string;
26
+ /** ioredis Sentinel master name forwarded as the Redis constructor `name` option. */
27
+ sentinelName?: string;
24
28
  /** Named Redis registrations remain scoped to their importing module. */
25
29
  global?: false;
26
30
  };
@@ -32,6 +36,6 @@ export type NamedRedisModuleOptions = RedisConnectionOptions & {
32
36
  */
33
37
  export type RedisModuleOptions = DefaultRedisModuleOptions | NamedRedisModuleOptions;
34
38
  /** Redis constructor options after Fluo module-only fields are removed. */
35
- export type RedisClientOptions = RedisConnectionOptions;
39
+ export type RedisClientOptions = RedisConnectionOptions & Pick<RedisOptions, 'name'>;
36
40
  export {};
37
41
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE5C,KAAK,sBAAsB,GAAG,IAAI,CAAC,YAAY,EAAE,aAAa,CAAC,CAAC;AAEhE,sEAAsE;AACtE,MAAM,WAAW,qBAAqB;IACpC,iJAAiJ;IACjJ,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,6JAA6J;IAC7J,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,kEAAkE;AAClE,MAAM,MAAM,yBAAyB,GAAG,sBAAsB,GAAG;IAC/D,wFAAwF;IACxF,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,2EAA2E;IAC3E,SAAS,CAAC,EAAE,qBAAqB,CAAC;IAClC,IAAI,CAAC,EAAE,SAAS,CAAC;CAClB,CAAC;AAEF,kEAAkE;AAClE,MAAM,MAAM,uBAAuB,GAAG,sBAAsB,GAAG;IAC7D,2EAA2E;IAC3E,SAAS,CAAC,EAAE,qBAAqB,CAAC;IAClC,2EAA2E;IAC3E,IAAI,EAAE,MAAM,CAAC;IACb,yEAAyE;IACzE,MAAM,CAAC,EAAE,KAAK,CAAC;CAChB,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,kBAAkB,GAAG,yBAAyB,GAAG,uBAAuB,CAAC;AAErF,2EAA2E;AAC3E,MAAM,MAAM,kBAAkB,GAAG,sBAAsB,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE5C,KAAK,sBAAsB,GAAG,IAAI,CAAC,YAAY,EAAE,aAAa,GAAG,MAAM,CAAC,CAAC;AAEzE,sEAAsE;AACtE,MAAM,WAAW,qBAAqB;IACpC,iJAAiJ;IACjJ,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,6JAA6J;IAC7J,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,kEAAkE;AAClE,MAAM,MAAM,yBAAyB,GAAG,sBAAsB,GAAG;IAC/D,wFAAwF;IACxF,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,2EAA2E;IAC3E,SAAS,CAAC,EAAE,qBAAqB,CAAC;IAClC,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,qFAAqF;IACrF,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,kEAAkE;AAClE,MAAM,MAAM,uBAAuB,GAAG,sBAAsB,GAAG;IAC7D,2EAA2E;IAC3E,SAAS,CAAC,EAAE,qBAAqB,CAAC;IAClC,2EAA2E;IAC3E,IAAI,EAAE,MAAM,CAAC;IACb,qFAAqF;IACrF,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,yEAAyE;IACzE,MAAM,CAAC,EAAE,KAAK,CAAC;CAChB,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,kBAAkB,GAAG,yBAAyB,GAAG,uBAAuB,CAAC;AAErF,2EAA2E;AAC3E,MAAM,MAAM,kBAAkB,GAAG,sBAAsB,GAAG,IAAI,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC"}
package/package.json CHANGED
@@ -9,7 +9,7 @@
9
9
  "connection",
10
10
  "lifecycle"
11
11
  ],
12
- "version": "1.0.2",
12
+ "version": "1.1.0",
13
13
  "private": false,
14
14
  "license": "MIT",
15
15
  "repository": {
@@ -36,9 +36,9 @@
36
36
  "dist"
37
37
  ],
38
38
  "dependencies": {
39
- "@fluojs/core": "^1.0.3",
40
- "@fluojs/di": "^1.1.0",
41
- "@fluojs/runtime": "^1.1.8"
39
+ "@fluojs/di": "^2.0.0",
40
+ "@fluojs/core": "^1.1.0",
41
+ "@fluojs/runtime": "^2.0.1"
42
42
  },
43
43
  "peerDependencies": {
44
44
  "ioredis": "^5.10.0"