@diia-inhouse/redis 2.30.21 → 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.
- package/dist/index.d.ts +10 -0
- package/dist/index.js +9 -20
- package/dist/interfaces/deps.d.ts +11 -0
- package/dist/interfaces/index.d.ts +4 -0
- package/dist/interfaces/index.js +3 -21
- package/dist/interfaces/mutex.d.ts +16 -0
- package/dist/interfaces/mutex.js +2 -6
- package/dist/interfaces/pubsub.d.ts +19 -0
- package/dist/interfaces/redis.d.ts +28 -0
- package/dist/interfaces/redis.js +12 -13
- package/dist/interfaces/store.d.ts +32 -0
- package/dist/services/index.d.ts +4 -0
- package/dist/services/index.js +5 -21
- package/dist/services/mutex.d.ts +19 -0
- package/dist/services/mutex.js +52 -44
- package/dist/services/providers/pubsub.js +96 -89
- package/dist/services/pubsub.d.ts +19 -0
- package/dist/services/pubsub.js +38 -43
- package/dist/services/redis.d.ts +10 -0
- package/dist/services/redis.js +84 -65
- package/dist/services/store.d.ts +47 -0
- package/dist/services/store.js +170 -183
- package/package.json +41 -32
- package/dist/index.js.map +0 -1
- package/dist/interfaces/deps.js +0 -3
- package/dist/interfaces/deps.js.map +0 -1
- package/dist/interfaces/index.js.map +0 -1
- package/dist/interfaces/mutex.js.map +0 -1
- package/dist/interfaces/pubsub.js +0 -3
- package/dist/interfaces/pubsub.js.map +0 -1
- package/dist/interfaces/redis.js.map +0 -1
- package/dist/interfaces/store.js +0 -3
- package/dist/interfaces/store.js.map +0 -1
- package/dist/services/index.js.map +0 -1
- package/dist/services/mutex.js.map +0 -1
- package/dist/services/providers/pubsub.js.map +0 -1
- package/dist/services/pubsub.js.map +0 -1
- package/dist/services/redis.js.map +0 -1
- package/dist/services/store.js.map +0 -1
- package/dist/types/index.d.ts +0 -3
- package/dist/types/interfaces/deps.d.ts +0 -6
- package/dist/types/interfaces/index.d.ts +0 -4
- package/dist/types/interfaces/mutex.d.ts +0 -13
- package/dist/types/interfaces/pubsub.d.ts +0 -15
- package/dist/types/interfaces/redis.d.ts +0 -24
- package/dist/types/interfaces/store.d.ts +0 -30
- package/dist/types/services/index.d.ts +0 -4
- package/dist/types/services/mutex.d.ts +0 -13
- package/dist/types/services/providers/pubsub.d.ts +0 -17
- package/dist/types/services/pubsub.d.ts +0 -15
- package/dist/types/services/redis.d.ts +0 -6
- package/dist/types/services/store.d.ts +0 -43
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { RedisConfig, RedisMode, RedisOptions, RedisStatus, RedisStatusValue, StoreStatus } from "./interfaces/redis.js";
|
|
2
|
+
import { MessageHandler, PubSubServiceProvider, PubSubStatus, PubSubStatusResult } from "./interfaces/pubsub.js";
|
|
3
|
+
import { Lock, LockOptions, MutexStatusResult, RedlockMutex } from "./interfaces/mutex.js";
|
|
4
|
+
import { SetValueOptions, StoreStatusResult, TaggedStoreValue, TagsConfig, ThrottleResult } from "./interfaces/store.js";
|
|
5
|
+
import { PubSubService } from "./services/pubsub.js";
|
|
6
|
+
import { RedisService } from "./services/redis.js";
|
|
7
|
+
import { StoreService } from "./services/store.js";
|
|
8
|
+
import { RedlockService } from "./services/mutex.js";
|
|
9
|
+
import { RedisDeps } from "./interfaces/deps.js";
|
|
10
|
+
export { Lock, LockOptions, MessageHandler, MutexStatusResult, PubSubService, PubSubServiceProvider, PubSubStatus, PubSubStatusResult, RedisConfig, RedisDeps, RedisMode, RedisOptions, RedisService, RedisStatus, RedisStatusValue, RedlockMutex, RedlockService, SetValueOptions, StoreService, StoreStatus, StoreStatusResult, TaggedStoreValue, TagsConfig, ThrottleResult };
|
package/dist/index.js
CHANGED
|
@@ -1,20 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
-
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
-
};
|
|
16
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
__exportStar(require("./interfaces"), exports);
|
|
18
|
-
__exportStar(require("./interfaces/deps"), exports);
|
|
19
|
-
__exportStar(require("./services"), exports);
|
|
20
|
-
//# sourceMappingURL=index.js.map
|
|
1
|
+
import { RedisMode, RedisStatusValue } from "./interfaces/redis.js";
|
|
2
|
+
import { RedlockMutex } from "./interfaces/mutex.js";
|
|
3
|
+
import "./interfaces/index.js";
|
|
4
|
+
import { RedisService } from "./services/redis.js";
|
|
5
|
+
import { PubSubService } from "./services/pubsub.js";
|
|
6
|
+
import { StoreService } from "./services/store.js";
|
|
7
|
+
import { RedlockService } from "./services/mutex.js";
|
|
8
|
+
import "./services/index.js";
|
|
9
|
+
export { PubSubService, RedisMode, RedisService, RedisStatusValue, RedlockMutex, RedlockService, StoreService };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { PubSubService } from "../services/pubsub.js";
|
|
2
|
+
import { StoreService } from "../services/store.js";
|
|
3
|
+
import { RedlockService } from "../services/mutex.js";
|
|
4
|
+
//#region src/interfaces/deps.d.ts
|
|
5
|
+
type RedisDeps = {
|
|
6
|
+
pubsub?: PubSubService;
|
|
7
|
+
redlock?: RedlockService;
|
|
8
|
+
store?: StoreService;
|
|
9
|
+
};
|
|
10
|
+
//#endregion
|
|
11
|
+
export { RedisDeps };
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { RedisConfig, RedisMode, RedisOptions, RedisStatus, RedisStatusValue, StoreStatus } from "./redis.js";
|
|
2
|
+
import { MessageHandler, PubSubServiceProvider, PubSubStatus, PubSubStatusResult } from "./pubsub.js";
|
|
3
|
+
import { Lock, LockOptions, MutexStatusResult, RedlockMutex } from "./mutex.js";
|
|
4
|
+
import { SetValueOptions, StoreStatusResult, TaggedStoreValue, TagsConfig, ThrottleResult } from "./store.js";
|
package/dist/interfaces/index.js
CHANGED
|
@@ -1,21 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
-
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
-
};
|
|
16
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
__exportStar(require("./pubsub"), exports);
|
|
18
|
-
__exportStar(require("./redis"), exports);
|
|
19
|
-
__exportStar(require("./mutex"), exports);
|
|
20
|
-
__exportStar(require("./store"), exports);
|
|
21
|
-
//# sourceMappingURL=index.js.map
|
|
1
|
+
import "./redis.js";
|
|
2
|
+
import "./mutex.js";
|
|
3
|
+
export {};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { RedlockMutex, RedlockMutex as RedlockMutex$1 } from "redis-semaphore";
|
|
2
|
+
|
|
3
|
+
//#region src/interfaces/mutex.d.ts
|
|
4
|
+
type Lock = RedlockMutex;
|
|
5
|
+
type MutexStatusResult = {
|
|
6
|
+
mutex: string;
|
|
7
|
+
};
|
|
8
|
+
type LockOptions = {
|
|
9
|
+
/**
|
|
10
|
+
* Time in milliseconds between acquire attempts if resource locked
|
|
11
|
+
* @defaultValue 500
|
|
12
|
+
*/
|
|
13
|
+
retryInterval?: number;
|
|
14
|
+
};
|
|
15
|
+
//#endregion
|
|
16
|
+
export { Lock, LockOptions, MutexStatusResult, RedlockMutex$1 as RedlockMutex };
|
package/dist/interfaces/mutex.js
CHANGED
|
@@ -1,6 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
exports.RedlockMutex = void 0;
|
|
4
|
-
var redis_semaphore_1 = require("redis-semaphore");
|
|
5
|
-
Object.defineProperty(exports, "RedlockMutex", { enumerable: true, get: function () { return redis_semaphore_1.RedlockMutex; } });
|
|
6
|
-
//# sourceMappingURL=mutex.js.map
|
|
1
|
+
import { RedlockMutex as RedlockMutex$1 } from "redis-semaphore";
|
|
2
|
+
export { RedlockMutex$1 as RedlockMutex };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { RedisStatus } from "./redis.js";
|
|
2
|
+
|
|
3
|
+
//#region src/interfaces/pubsub.d.ts
|
|
4
|
+
interface PubSubStatus {
|
|
5
|
+
pub: RedisStatus;
|
|
6
|
+
sub: RedisStatus;
|
|
7
|
+
}
|
|
8
|
+
type PubSubStatusResult = {
|
|
9
|
+
pubsub: PubSubStatus;
|
|
10
|
+
};
|
|
11
|
+
type MessageHandler = (message: string) => Promise<unknown>;
|
|
12
|
+
interface PubSubServiceProvider {
|
|
13
|
+
unsubscribe(channel: string): Promise<unknown>;
|
|
14
|
+
publish(channel: string, data: unknown): Promise<number>;
|
|
15
|
+
onceChannelMessage(channel: string, handler: MessageHandler): Promise<void>;
|
|
16
|
+
getStatus(): PubSubStatus;
|
|
17
|
+
}
|
|
18
|
+
//#endregion
|
|
19
|
+
export { MessageHandler, PubSubServiceProvider, PubSubStatus, PubSubStatusResult };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { RedisOptions } from "ioredis";
|
|
2
|
+
|
|
3
|
+
//#region src/interfaces/redis.d.ts
|
|
4
|
+
declare enum RedisMode {
|
|
5
|
+
ReadWrite = "READ-WRITE",
|
|
6
|
+
ReadOnly = "READ-ONLY"
|
|
7
|
+
}
|
|
8
|
+
interface RedisOptions$1 extends RedisOptions {
|
|
9
|
+
maxRetryAttempts?: number;
|
|
10
|
+
initialRetryDelay?: number;
|
|
11
|
+
maxRetryDelay?: number;
|
|
12
|
+
redisMode?: RedisMode;
|
|
13
|
+
}
|
|
14
|
+
declare enum RedisStatusValue {
|
|
15
|
+
Ready = "ready"
|
|
16
|
+
}
|
|
17
|
+
type RedisStatus = RedisStatusValue | string;
|
|
18
|
+
interface RedisConfig {
|
|
19
|
+
readWrite: RedisOptions$1;
|
|
20
|
+
readOnly: RedisOptions$1;
|
|
21
|
+
enablePubsub?: boolean;
|
|
22
|
+
}
|
|
23
|
+
interface StoreStatus {
|
|
24
|
+
readWrite: RedisStatus;
|
|
25
|
+
readOnly: RedisStatus;
|
|
26
|
+
}
|
|
27
|
+
//#endregion
|
|
28
|
+
export { RedisConfig, RedisMode, RedisOptions$1 as RedisOptions, RedisStatus, RedisStatusValue, StoreStatus };
|
package/dist/interfaces/redis.js
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
(
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
//# sourceMappingURL=redis.js.map
|
|
1
|
+
//#region src/interfaces/redis.ts
|
|
2
|
+
let RedisMode = /* @__PURE__ */ function(RedisMode) {
|
|
3
|
+
RedisMode["ReadWrite"] = "READ-WRITE";
|
|
4
|
+
RedisMode["ReadOnly"] = "READ-ONLY";
|
|
5
|
+
return RedisMode;
|
|
6
|
+
}({});
|
|
7
|
+
let RedisStatusValue = /* @__PURE__ */ function(RedisStatusValue) {
|
|
8
|
+
RedisStatusValue["Ready"] = "ready";
|
|
9
|
+
return RedisStatusValue;
|
|
10
|
+
}({});
|
|
11
|
+
//#endregion
|
|
12
|
+
export { RedisMode, RedisStatusValue };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { StoreStatus } from "./redis.js";
|
|
2
|
+
|
|
3
|
+
//#region src/interfaces/store.d.ts
|
|
4
|
+
type TagsConfig = { [tag in string]?: number };
|
|
5
|
+
interface TaggedStoreValue {
|
|
6
|
+
data: string;
|
|
7
|
+
timestamp: number;
|
|
8
|
+
tags: string[];
|
|
9
|
+
}
|
|
10
|
+
interface SetValueOptions {
|
|
11
|
+
/**
|
|
12
|
+
* Time to live in milliseconds.
|
|
13
|
+
* If not set, the key will be permanent.
|
|
14
|
+
*/
|
|
15
|
+
ttl?: number;
|
|
16
|
+
/**
|
|
17
|
+
* Tags associated with the value.
|
|
18
|
+
*/
|
|
19
|
+
tags?: string[];
|
|
20
|
+
}
|
|
21
|
+
interface ThrottleResult {
|
|
22
|
+
limited: boolean;
|
|
23
|
+
totalLimit: number;
|
|
24
|
+
remaining: number;
|
|
25
|
+
retryAfterSec: number;
|
|
26
|
+
resetAfterSec: number;
|
|
27
|
+
}
|
|
28
|
+
type StoreStatusResult = {
|
|
29
|
+
store: StoreStatus;
|
|
30
|
+
};
|
|
31
|
+
//#endregion
|
|
32
|
+
export { SetValueOptions, StoreStatusResult, TaggedStoreValue, TagsConfig, ThrottleResult };
|
package/dist/services/index.js
CHANGED
|
@@ -1,21 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
-
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
-
};
|
|
16
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
__exportStar(require("./pubsub"), exports);
|
|
18
|
-
__exportStar(require("./redis"), exports);
|
|
19
|
-
__exportStar(require("./store"), exports);
|
|
20
|
-
__exportStar(require("./mutex"), exports);
|
|
21
|
-
//# sourceMappingURL=index.js.map
|
|
1
|
+
import "./redis.js";
|
|
2
|
+
import "./pubsub.js";
|
|
3
|
+
import "./store.js";
|
|
4
|
+
import "./mutex.js";
|
|
5
|
+
export {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { RedisConfig } from "../interfaces/redis.js";
|
|
2
|
+
import { LockOptions, MutexStatusResult } from "../interfaces/mutex.js";
|
|
3
|
+
import { RedlockMutex } from "redis-semaphore";
|
|
4
|
+
import { HealthCheckResult, Logger, OnDestroy, OnHealthCheck } from "@diia-inhouse/types";
|
|
5
|
+
|
|
6
|
+
//#region src/services/mutex.d.ts
|
|
7
|
+
declare class RedlockService implements OnHealthCheck, OnDestroy {
|
|
8
|
+
private readonly storeConfig;
|
|
9
|
+
private readonly logger;
|
|
10
|
+
private clientRW;
|
|
11
|
+
constructor(storeConfig: RedisConfig, logger: Logger);
|
|
12
|
+
onHealthCheck(): Promise<HealthCheckResult<MutexStatusResult>>;
|
|
13
|
+
onDestroy(): Promise<void>;
|
|
14
|
+
lock(resource: string, ttl?: number, {
|
|
15
|
+
retryInterval
|
|
16
|
+
}?: LockOptions): Promise<RedlockMutex>;
|
|
17
|
+
}
|
|
18
|
+
//#endregion
|
|
19
|
+
export { RedlockService };
|
package/dist/services/mutex.js
CHANGED
|
@@ -1,44 +1,52 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
1
|
+
import "../interfaces/redis.js";
|
|
2
|
+
import { RedisService } from "./redis.js";
|
|
3
|
+
import { RedlockMutex } from "redis-semaphore";
|
|
4
|
+
import { HttpStatusCode } from "@diia-inhouse/types";
|
|
5
|
+
//#region src/services/mutex.ts
|
|
6
|
+
var RedlockService = class {
|
|
7
|
+
storeConfig;
|
|
8
|
+
logger;
|
|
9
|
+
clientRW;
|
|
10
|
+
constructor(storeConfig, logger) {
|
|
11
|
+
this.storeConfig = storeConfig;
|
|
12
|
+
this.logger = logger;
|
|
13
|
+
const { readWrite } = this.storeConfig;
|
|
14
|
+
this.clientRW = RedisService.createClient({
|
|
15
|
+
...readWrite,
|
|
16
|
+
redisMode: "READ-WRITE"
|
|
17
|
+
}, this.logger);
|
|
18
|
+
this.clientRW.on("connect", () => {
|
|
19
|
+
const { host, port, sentinels } = readWrite;
|
|
20
|
+
this.logger.info("Redis REDLOCK READ-WRITE connection open", {
|
|
21
|
+
host,
|
|
22
|
+
port,
|
|
23
|
+
sentinels
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
this.clientRW.on("error", (err) => {
|
|
27
|
+
this.logger.error("Redis REDLOCK READ-WRITE connection error ", { err });
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
async onHealthCheck() {
|
|
31
|
+
const cacheStatus = this.clientRW.status;
|
|
32
|
+
return {
|
|
33
|
+
status: cacheStatus === "ready" ? HttpStatusCode.OK : HttpStatusCode.SERVICE_UNAVAILABLE,
|
|
34
|
+
details: { mutex: cacheStatus }
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
async onDestroy() {
|
|
38
|
+
await this.clientRW.quit();
|
|
39
|
+
}
|
|
40
|
+
async lock(resource, ttl = 6e4, { retryInterval = 500 } = {}) {
|
|
41
|
+
this.logger.info(`Start LOCK resource [${resource}] for ttl [${ttl}]ms`);
|
|
42
|
+
const mutex = new RedlockMutex([this.clientRW], resource, {
|
|
43
|
+
lockTimeout: ttl,
|
|
44
|
+
acquireTimeout: ttl * 2,
|
|
45
|
+
retryInterval
|
|
46
|
+
});
|
|
47
|
+
await mutex.acquire();
|
|
48
|
+
return mutex;
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
//#endregion
|
|
52
|
+
export { RedlockService };
|
|
@@ -1,89 +1,96 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
|
|
1
|
+
import "../../interfaces/redis.js";
|
|
2
|
+
import { RedisService } from "../redis.js";
|
|
3
|
+
//#region src/services/providers/pubsub.ts
|
|
4
|
+
var PubSubProvider = class {
|
|
5
|
+
logger;
|
|
6
|
+
pub;
|
|
7
|
+
sub;
|
|
8
|
+
oneTimeHandlerByChannel = {};
|
|
9
|
+
handlerByChannel = {};
|
|
10
|
+
constructor({ readWrite }, logger) {
|
|
11
|
+
this.logger = logger;
|
|
12
|
+
this.pub = RedisService.createClient({
|
|
13
|
+
...readWrite,
|
|
14
|
+
redisMode: "READ-WRITE"
|
|
15
|
+
}, this.logger);
|
|
16
|
+
this.sub = RedisService.createClient({
|
|
17
|
+
...readWrite,
|
|
18
|
+
redisMode: "READ-WRITE",
|
|
19
|
+
autoResubscribe: true
|
|
20
|
+
}, this.logger);
|
|
21
|
+
this.pub.on("connect", () => {
|
|
22
|
+
const { host, port, sentinels } = readWrite;
|
|
23
|
+
this.logger.info("Redis READ-WRITE pub connection open", {
|
|
24
|
+
host,
|
|
25
|
+
port,
|
|
26
|
+
sentinels
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
this.pub.on("error", (err) => {
|
|
30
|
+
this.logger.error("Redis READ-WRITE pub connection error ", { err });
|
|
31
|
+
});
|
|
32
|
+
this.sub.on("connect", () => {
|
|
33
|
+
const { host, port, sentinels } = readWrite;
|
|
34
|
+
this.logger.info("Redis READ-WRITE sub connection open", {
|
|
35
|
+
host,
|
|
36
|
+
port,
|
|
37
|
+
sentinels
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
this.sub.on("error", (err) => {
|
|
41
|
+
this.logger.error("Redis READ-WRITE sub connection error ", { err });
|
|
42
|
+
});
|
|
43
|
+
this.sub.on("message", async (channel, message) => {
|
|
44
|
+
const oneTimeHandler = this.oneTimeHandlerByChannel[channel];
|
|
45
|
+
if (oneTimeHandler) {
|
|
46
|
+
delete this.oneTimeHandlerByChannel[channel];
|
|
47
|
+
await this.sub.unsubscribe(channel);
|
|
48
|
+
try {
|
|
49
|
+
await oneTimeHandler(message);
|
|
50
|
+
} catch (err) {
|
|
51
|
+
this.logger.error(`Failed to handle message from the channel ${channel}`, { err });
|
|
52
|
+
}
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const handlerByChannel = this.handlerByChannel[channel];
|
|
56
|
+
if (handlerByChannel) {
|
|
57
|
+
try {
|
|
58
|
+
await handlerByChannel(message);
|
|
59
|
+
} catch (err) {
|
|
60
|
+
this.logger.error(`Failed to handle message from the channel ${channel}`, { err });
|
|
61
|
+
}
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
this.logger.error(`Could not find a message handler for the channel ${channel}`);
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
async unsubscribe(channel) {
|
|
68
|
+
delete this.oneTimeHandlerByChannel[channel];
|
|
69
|
+
delete this.handlerByChannel[channel];
|
|
70
|
+
return await this.sub.unsubscribe(channel);
|
|
71
|
+
}
|
|
72
|
+
async publish(channel, data) {
|
|
73
|
+
return await this.pub.publish(channel, JSON.stringify(data));
|
|
74
|
+
}
|
|
75
|
+
async onChannelMessage(channel, handler) {
|
|
76
|
+
if (Object.keys(this.handlerByChannel).includes(channel)) throw new Error(`Handler already exists by the provided channel ${channel}`);
|
|
77
|
+
this.handlerByChannel[channel] = handler;
|
|
78
|
+
await this.sub.subscribe(channel);
|
|
79
|
+
}
|
|
80
|
+
async onceChannelMessage(channel, handler) {
|
|
81
|
+
if (Object.keys(this.oneTimeHandlerByChannel).includes(channel)) throw new Error(`Handler already exists by the provided channel ${channel}`);
|
|
82
|
+
this.oneTimeHandlerByChannel[channel] = handler;
|
|
83
|
+
await this.sub.subscribe(channel);
|
|
84
|
+
}
|
|
85
|
+
async quit() {
|
|
86
|
+
await Promise.all([this.pub.quit(), this.sub.quit()]);
|
|
87
|
+
}
|
|
88
|
+
getStatus() {
|
|
89
|
+
return {
|
|
90
|
+
pub: this.pub.status,
|
|
91
|
+
sub: this.sub.status
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
//#endregion
|
|
96
|
+
export { PubSubProvider };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { RedisConfig } from "../interfaces/redis.js";
|
|
2
|
+
import { MessageHandler, PubSubStatusResult } from "../interfaces/pubsub.js";
|
|
3
|
+
import { HealthCheckResult, Logger, OnDestroy, OnHealthCheck } from "@diia-inhouse/types";
|
|
4
|
+
|
|
5
|
+
//#region src/services/pubsub.d.ts
|
|
6
|
+
declare class PubSubService implements OnHealthCheck, OnDestroy {
|
|
7
|
+
private readonly redisConfig;
|
|
8
|
+
private readonly logger;
|
|
9
|
+
private readonly provider;
|
|
10
|
+
constructor(redisConfig: RedisConfig, logger: Logger);
|
|
11
|
+
onHealthCheck(): Promise<HealthCheckResult<PubSubStatusResult>>;
|
|
12
|
+
onDestroy(): Promise<void>;
|
|
13
|
+
unsubscribe(channel: string): Promise<unknown>;
|
|
14
|
+
publish(channel: string, data: unknown): Promise<number>;
|
|
15
|
+
onceChannelMessage(channel: string, handler: MessageHandler): Promise<void>;
|
|
16
|
+
onChannelMessage(channel: string, handler: MessageHandler): Promise<void>;
|
|
17
|
+
}
|
|
18
|
+
//#endregion
|
|
19
|
+
export { PubSubService };
|