@diia-inhouse/redis 2.30.16 → 3.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.
Files changed (52) hide show
  1. package/dist/index.d.ts +10 -0
  2. package/dist/index.js +9 -20
  3. package/dist/interfaces/deps.d.ts +11 -0
  4. package/dist/interfaces/index.d.ts +4 -0
  5. package/dist/interfaces/index.js +3 -21
  6. package/dist/interfaces/mutex.d.ts +16 -0
  7. package/dist/interfaces/mutex.js +2 -6
  8. package/dist/interfaces/pubsub.d.ts +19 -0
  9. package/dist/interfaces/redis.d.ts +28 -0
  10. package/dist/interfaces/redis.js +12 -13
  11. package/dist/interfaces/store.d.ts +32 -0
  12. package/dist/services/index.d.ts +4 -0
  13. package/dist/services/index.js +5 -21
  14. package/dist/services/mutex.d.ts +19 -0
  15. package/dist/services/mutex.js +52 -44
  16. package/dist/services/providers/pubsub.js +96 -89
  17. package/dist/services/pubsub.d.ts +19 -0
  18. package/dist/services/pubsub.js +38 -43
  19. package/dist/services/redis.d.ts +10 -0
  20. package/dist/services/redis.js +84 -65
  21. package/dist/services/store.d.ts +47 -0
  22. package/dist/services/store.js +170 -183
  23. package/package.json +41 -32
  24. package/dist/index.js.map +0 -1
  25. package/dist/interfaces/deps.js +0 -3
  26. package/dist/interfaces/deps.js.map +0 -1
  27. package/dist/interfaces/index.js.map +0 -1
  28. package/dist/interfaces/mutex.js.map +0 -1
  29. package/dist/interfaces/pubsub.js +0 -3
  30. package/dist/interfaces/pubsub.js.map +0 -1
  31. package/dist/interfaces/redis.js.map +0 -1
  32. package/dist/interfaces/store.js +0 -3
  33. package/dist/interfaces/store.js.map +0 -1
  34. package/dist/services/index.js.map +0 -1
  35. package/dist/services/mutex.js.map +0 -1
  36. package/dist/services/providers/pubsub.js.map +0 -1
  37. package/dist/services/pubsub.js.map +0 -1
  38. package/dist/services/redis.js.map +0 -1
  39. package/dist/services/store.js.map +0 -1
  40. package/dist/types/index.d.ts +0 -3
  41. package/dist/types/interfaces/deps.d.ts +0 -6
  42. package/dist/types/interfaces/index.d.ts +0 -4
  43. package/dist/types/interfaces/mutex.d.ts +0 -13
  44. package/dist/types/interfaces/pubsub.d.ts +0 -15
  45. package/dist/types/interfaces/redis.d.ts +0 -24
  46. package/dist/types/interfaces/store.d.ts +0 -30
  47. package/dist/types/services/index.d.ts +0 -4
  48. package/dist/types/services/mutex.d.ts +0 -13
  49. package/dist/types/services/providers/pubsub.d.ts +0 -17
  50. package/dist/types/services/pubsub.d.ts +0 -15
  51. package/dist/types/services/redis.d.ts +0 -6
  52. package/dist/types/services/store.d.ts +0 -43
@@ -1,43 +1,38 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.PubSubService = void 0;
4
- const types_1 = require("@diia-inhouse/types");
5
- const redis_1 = require("../interfaces/redis");
6
- const pubsub_1 = require("./providers/pubsub");
7
- class PubSubService {
8
- redisConfig;
9
- logger;
10
- provider;
11
- constructor(redisConfig, logger) {
12
- this.redisConfig = redisConfig;
13
- this.logger = logger;
14
- this.provider = new pubsub_1.PubSubProvider(this.redisConfig, this.logger);
15
- }
16
- async onHealthCheck() {
17
- const pubSubStatus = this.provider.getStatus();
18
- const status = Object.values(pubSubStatus).some((s) => s !== redis_1.RedisStatusValue.Ready)
19
- ? types_1.HttpStatusCode.SERVICE_UNAVAILABLE
20
- : types_1.HttpStatusCode.OK;
21
- return {
22
- status,
23
- details: { pubsub: pubSubStatus },
24
- };
25
- }
26
- async onDestroy() {
27
- await this.provider.quit();
28
- }
29
- async unsubscribe(channel) {
30
- return await this.provider.unsubscribe(channel);
31
- }
32
- async publish(channel, data) {
33
- return await this.provider.publish(channel, data);
34
- }
35
- onceChannelMessage(channel, handler) {
36
- return this.provider.onceChannelMessage(channel, handler);
37
- }
38
- async onChannelMessage(channel, handler) {
39
- return await this.provider.onChannelMessage(channel, handler);
40
- }
41
- }
42
- exports.PubSubService = PubSubService;
43
- //# sourceMappingURL=pubsub.js.map
1
+ import "../interfaces/redis.js";
2
+ import { PubSubProvider } from "./providers/pubsub.js";
3
+ import { HttpStatusCode } from "@diia-inhouse/types";
4
+ //#region src/services/pubsub.ts
5
+ var PubSubService = class {
6
+ redisConfig;
7
+ logger;
8
+ provider;
9
+ constructor(redisConfig, logger) {
10
+ this.redisConfig = redisConfig;
11
+ this.logger = logger;
12
+ this.provider = new PubSubProvider(this.redisConfig, this.logger);
13
+ }
14
+ async onHealthCheck() {
15
+ const pubSubStatus = this.provider.getStatus();
16
+ return {
17
+ status: Object.values(pubSubStatus).some((s) => s !== "ready") ? HttpStatusCode.SERVICE_UNAVAILABLE : HttpStatusCode.OK,
18
+ details: { pubsub: pubSubStatus }
19
+ };
20
+ }
21
+ async onDestroy() {
22
+ await this.provider.quit();
23
+ }
24
+ async unsubscribe(channel) {
25
+ return await this.provider.unsubscribe(channel);
26
+ }
27
+ async publish(channel, data) {
28
+ return await this.provider.publish(channel, data);
29
+ }
30
+ onceChannelMessage(channel, handler) {
31
+ return this.provider.onceChannelMessage(channel, handler);
32
+ }
33
+ async onChannelMessage(channel, handler) {
34
+ return await this.provider.onChannelMessage(channel, handler);
35
+ }
36
+ };
37
+ //#endregion
38
+ export { PubSubService };
@@ -0,0 +1,10 @@
1
+ import { RedisOptions as RedisOptions$1 } from "../interfaces/redis.js";
2
+ import { Logger } from "@diia-inhouse/types";
3
+ import { Redis } from "ioredis";
4
+
5
+ //#region src/services/redis.d.ts
6
+ declare const RedisService: {
7
+ createClient(extendedRedisOptions: RedisOptions$1, logger: Logger): Redis;
8
+ };
9
+ //#endregion
10
+ export { RedisService };
@@ -1,65 +1,84 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.RedisService = void 0;
7
- const ioredis_1 = __importDefault(require("ioredis"));
8
- const types_1 = require("@diia-inhouse/types");
9
- exports.RedisService = {
10
- createClient(extendedRedisOptions, logger) {
11
- const { maxRetryAttempts = 10, initialRetryDelay = types_1.DurationMs.Second, maxRetryDelay = types_1.DurationMs.Second * 10, ...options } = extendedRedisOptions;
12
- const { host, port, redisMode } = options;
13
- const redisOptions = {
14
- keepAlive: types_1.DurationMs.Second * 10,
15
- enableAutoPipelining: true,
16
- reconnectOnError: (err) => {
17
- logger.error('Redis error detected due:', { err, host, port, redisMode });
18
- const targetError = 'READONLY';
19
- if (err.message.includes(targetError)) {
20
- // Force reconnect and resend the failed command after reconnection
21
- // https://github.com/redis/ioredis?tab=readme-ov-file#reconnect-on-error
22
- logger.warn('Redis encountered READONLY error, forcing reconnect', { host, port, redisMode });
23
- return 2;
24
- }
25
- return false;
26
- },
27
- retryStrategy: (attempts) => {
28
- if (attempts > maxRetryAttempts) {
29
- logger.error(`Redis connection failed after ${maxRetryAttempts} attempts. Shutting down connection attempts.`, {
30
- host,
31
- port,
32
- redisMode,
33
- });
34
- return null; // Stop retrying (null instead of false)
35
- }
36
- const delay = Math.min(initialRetryDelay * Math.pow(2, attempts - 1), maxRetryDelay);
37
- logger.debug(`Redis connection attempt ${attempts} failed. Retrying in ${delay}ms...`, {
38
- host,
39
- port,
40
- redisMode,
41
- });
42
- return delay;
43
- },
44
- ...options,
45
- };
46
- const client = new ioredis_1.default(redisOptions);
47
- client.on('ready', () => {
48
- logger.debug('Redis client is ready to accept commands', { host, port, redisMode });
49
- });
50
- client.on('close', () => {
51
- logger.debug('Redis connection closed', { host, port, redisMode });
52
- });
53
- client.on('reconnecting', (timeToReconnect) => {
54
- logger.debug(`Redis client is reconnecting in ${timeToReconnect}ms`, { host, port, redisMode });
55
- });
56
- client.on('end', () => {
57
- logger.debug('Redis connection ended, no more reconnection attempts will be made', { host, port, redisMode });
58
- });
59
- client.on('wait', () => {
60
- logger.debug('Redis client is waiting to reconnect', { host, port, redisMode });
61
- });
62
- return client;
63
- },
64
- };
65
- //# sourceMappingURL=redis.js.map
1
+ import { DurationMs } from "@diia-inhouse/types";
2
+ import { Redis } from "ioredis";
3
+ //#region src/services/redis.ts
4
+ const RedisService = { createClient(extendedRedisOptions, logger) {
5
+ const { maxRetryAttempts = 10, initialRetryDelay = DurationMs.Second, maxRetryDelay = DurationMs.Second * 10, ...options } = extendedRedisOptions;
6
+ const { host, port, redisMode } = options;
7
+ const client = new Redis({
8
+ keepAlive: DurationMs.Second * 10,
9
+ enableAutoPipelining: true,
10
+ reconnectOnError: (err) => {
11
+ logger.error("Redis error detected due:", {
12
+ err,
13
+ host,
14
+ port,
15
+ redisMode
16
+ });
17
+ if (err.message.includes("READONLY")) {
18
+ logger.warn("Redis encountered READONLY error, forcing reconnect", {
19
+ host,
20
+ port,
21
+ redisMode
22
+ });
23
+ return 2;
24
+ }
25
+ return false;
26
+ },
27
+ retryStrategy: (attempts) => {
28
+ if (attempts > maxRetryAttempts) {
29
+ logger.error(`Redis connection failed after ${maxRetryAttempts} attempts. Shutting down connection attempts.`, {
30
+ host,
31
+ port,
32
+ redisMode
33
+ });
34
+ return null;
35
+ }
36
+ const delay = Math.min(initialRetryDelay * Math.pow(2, attempts - 1), maxRetryDelay);
37
+ logger.debug(`Redis connection attempt ${attempts} failed. Retrying in ${delay}ms...`, {
38
+ host,
39
+ port,
40
+ redisMode
41
+ });
42
+ return delay;
43
+ },
44
+ ...options
45
+ });
46
+ client.on("ready", () => {
47
+ logger.debug("Redis client is ready to accept commands", {
48
+ host,
49
+ port,
50
+ redisMode
51
+ });
52
+ });
53
+ client.on("close", () => {
54
+ logger.debug("Redis connection closed", {
55
+ host,
56
+ port,
57
+ redisMode
58
+ });
59
+ });
60
+ client.on("reconnecting", (timeToReconnect) => {
61
+ logger.debug(`Redis client is reconnecting in ${timeToReconnect}ms`, {
62
+ host,
63
+ port,
64
+ redisMode
65
+ });
66
+ });
67
+ client.on("end", () => {
68
+ logger.debug("Redis connection ended, no more reconnection attempts will be made", {
69
+ host,
70
+ port,
71
+ redisMode
72
+ });
73
+ });
74
+ client.on("wait", () => {
75
+ logger.debug("Redis client is waiting to reconnect", {
76
+ host,
77
+ port,
78
+ redisMode
79
+ });
80
+ });
81
+ return client;
82
+ } };
83
+ //#endregion
84
+ export { RedisService };
@@ -0,0 +1,47 @@
1
+ import { RedisConfig } from "../interfaces/redis.js";
2
+ import { SetValueOptions, StoreStatusResult, ThrottleResult } from "../interfaces/store.js";
3
+ import { HealthCheckResult, Logger, OnDestroy, OnHealthCheck } from "@diia-inhouse/types";
4
+
5
+ //#region src/services/store.d.ts
6
+ declare class StoreService implements OnHealthCheck, OnDestroy {
7
+ private readonly storeConfig;
8
+ private readonly logger;
9
+ private clientRW;
10
+ private clientRO;
11
+ private tagsKey;
12
+ constructor(storeConfig: RedisConfig, logger: Logger);
13
+ onHealthCheck(): Promise<HealthCheckResult<StoreStatusResult>>;
14
+ onDestroy(): Promise<void>;
15
+ get(key: string): Promise<string | null>;
16
+ mget(...keys: string[]): Promise<(string | null)[]>;
17
+ hget(key: string, field: string): Promise<string | null>;
18
+ hlen(key: string): Promise<number | null>;
19
+ hgetall(key: string): Promise<Record<string, string> | null>;
20
+ hvals(key: string): Promise<string[]>;
21
+ hscan(key: string, cursor: number | string, count: number): Promise<{
22
+ cursor: string;
23
+ elements: string[];
24
+ }>;
25
+ scan(matchPattern: string, cursor: number | string, count: number): Promise<{
26
+ cursor: string;
27
+ elements: string[];
28
+ }>;
29
+ lrange(key: string, start: number, stop: number): Promise<string[] | null>;
30
+ getUsingTags(key: string): Promise<string | null>;
31
+ set(key: string, value: string, options?: SetValueOptions): Promise<"OK" | null>;
32
+ hset(key: string, value: Record<string, string>): Promise<number>;
33
+ lpush(key: string, ...values: string[]): Promise<number>;
34
+ incrby(key: string, value: number): Promise<number>;
35
+ keys(pattern: string): Promise<string[]>;
36
+ remember(key: string, closure: () => Promise<string | null>, options?: SetValueOptions): Promise<string | null>;
37
+ remove(...keys: string[]): Promise<number>;
38
+ hdel(key: string, ...fields: string[]): Promise<number>;
39
+ expire(key: string, seconds: number): Promise<number>;
40
+ bumpTags(tags: string[]): Promise<"OK" | null>;
41
+ throttle(key: string, maxBurst: number, rate: number, periodSec: number, quantity?: number): Promise<ThrottleResult>;
42
+ flushDb(): Promise<"OK">;
43
+ private validate;
44
+ private wrapValueWithMetadata;
45
+ }
46
+ //#endregion
47
+ export { StoreService };