redis-consumer 1.1.2 → 1.1.3
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/client.d.ts +27 -0
- package/dist/client.js +39 -0
- package/dist/consumer.d.ts +52 -0
- package/dist/consumer.js +162 -0
- package/dist/helpers.d.ts +2 -0
- package/dist/helpers.js +5 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +22 -0
- package/dist/producer.d.ts +8 -0
- package/dist/producer.js +13 -0
- package/dist/retry-processor.d.ts +36 -0
- package/dist/retry-processor.js +84 -0
- package/package.json +2 -2
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { RedisScripts } from 'redis';
|
|
2
|
+
import { RedisClientOptions } from 'redis';
|
|
3
|
+
import { RedisConsumer, ConsumerOptions, ProcessErrorData } from './consumer';
|
|
4
|
+
import { RedisProducer } from './producer';
|
|
5
|
+
import { RetryFailedMessage, RetryMessage } from './retry-processor';
|
|
6
|
+
declare const InstRedisClient: import("@redis/client/dist/lib/client").InstantiableRedisClient<import("redis").RedisModules, import("redis").RedisFunctions, RedisScripts>;
|
|
7
|
+
interface AdditionalClientOptions {
|
|
8
|
+
groupName: string;
|
|
9
|
+
clientName: string;
|
|
10
|
+
}
|
|
11
|
+
export declare interface RedisClient<S extends RedisScripts = RedisScripts> {
|
|
12
|
+
on(event: 'process-error', listener: (err: Error, data: ProcessErrorData) => void): this;
|
|
13
|
+
on(event: 'retry-failed', listener: (err: Error, data: RetryFailedMessage) => void): this;
|
|
14
|
+
on(event: 'retry', listener: (data: RetryMessage) => void): this;
|
|
15
|
+
on(event: string, listener: (data: any) => void): this;
|
|
16
|
+
}
|
|
17
|
+
export declare class RedisClient<S extends RedisScripts> extends InstRedisClient {
|
|
18
|
+
readonly groupName: string;
|
|
19
|
+
readonly clientName: string;
|
|
20
|
+
constructor(options: Omit<RedisClientOptions<never, never, S>, 'modules'> & AdditionalClientOptions);
|
|
21
|
+
createConsumer<S extends RedisScripts>(options?: ConsumerOptions): RedisConsumer<S>;
|
|
22
|
+
createProducer(): RedisProducer<S>;
|
|
23
|
+
streamExists(key: string): Promise<number>;
|
|
24
|
+
groupExists(key: string): Promise<boolean>;
|
|
25
|
+
createGroup(key: string): Promise<string>;
|
|
26
|
+
}
|
|
27
|
+
export {};
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
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.RedisClient = void 0;
|
|
7
|
+
const client_1 = __importDefault(require("@redis/client/dist/lib/client"));
|
|
8
|
+
const consumer_1 = require("./consumer");
|
|
9
|
+
const producer_1 = require("./producer");
|
|
10
|
+
const InstRedisClient = client_1.default.extend();
|
|
11
|
+
class RedisClient extends InstRedisClient {
|
|
12
|
+
groupName;
|
|
13
|
+
clientName;
|
|
14
|
+
constructor(options) {
|
|
15
|
+
super(options);
|
|
16
|
+
this.groupName = options.groupName;
|
|
17
|
+
this.clientName = options.clientName;
|
|
18
|
+
}
|
|
19
|
+
createConsumer(options) {
|
|
20
|
+
return new consumer_1.RedisConsumer(this, options);
|
|
21
|
+
}
|
|
22
|
+
createProducer() {
|
|
23
|
+
return new producer_1.RedisProducer(this);
|
|
24
|
+
}
|
|
25
|
+
async streamExists(key) {
|
|
26
|
+
return await this.exists(key);
|
|
27
|
+
}
|
|
28
|
+
async groupExists(key) {
|
|
29
|
+
if (!(await this.streamExists(key)))
|
|
30
|
+
return false;
|
|
31
|
+
const groupInfo = await this.xInfoGroups(key);
|
|
32
|
+
return groupInfo.length > 0;
|
|
33
|
+
}
|
|
34
|
+
async createGroup(key) {
|
|
35
|
+
const result = await this.xGroupCreate(key, this.groupName, '$', { MKSTREAM: true });
|
|
36
|
+
return result;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
exports.RedisClient = RedisClient;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { RedisClientType, RedisScripts } from 'redis';
|
|
2
|
+
import { StreamMessageReply as OriginalStreamMessageReply } from '@redis/client/dist/lib/commands/generic-transformers';
|
|
3
|
+
import { StreamMessageData, StreamMessageId } from '.';
|
|
4
|
+
import { RedisClient } from './client';
|
|
5
|
+
export type StreamMessageReply<T = StreamMessageData> = Omit<OriginalStreamMessageReply, 'message'> & {
|
|
6
|
+
message: T;
|
|
7
|
+
};
|
|
8
|
+
export type StreamProcessingFunction<T> = (data: StreamMessageReply<T>, stream: string) => void;
|
|
9
|
+
export interface StreamToListen {
|
|
10
|
+
name: string;
|
|
11
|
+
executable: StreamProcessingFunction<any>;
|
|
12
|
+
id?: string;
|
|
13
|
+
}
|
|
14
|
+
export type StreamsToListen = StreamToListen[];
|
|
15
|
+
export interface ConsumerOptions {
|
|
16
|
+
COUNT?: number;
|
|
17
|
+
BLOCK?: number;
|
|
18
|
+
retries?: number;
|
|
19
|
+
retryTime?: string[];
|
|
20
|
+
}
|
|
21
|
+
export interface ProcessErrorData {
|
|
22
|
+
stream: string;
|
|
23
|
+
message: OriginalStreamMessageReply;
|
|
24
|
+
retries: number;
|
|
25
|
+
}
|
|
26
|
+
export declare class RedisConsumer<S extends RedisScripts = RedisScripts> {
|
|
27
|
+
client: RedisClientType<any, any, any>;
|
|
28
|
+
private originalClient;
|
|
29
|
+
private state;
|
|
30
|
+
private retryProcessor;
|
|
31
|
+
private successfullMessages;
|
|
32
|
+
private BLOCK;
|
|
33
|
+
private COUNT;
|
|
34
|
+
private RETRIES;
|
|
35
|
+
constructor(client: RedisClient<S>, options?: ConsumerOptions);
|
|
36
|
+
set block(block: number);
|
|
37
|
+
set count(count: number);
|
|
38
|
+
set retries(retries: number);
|
|
39
|
+
get settings(): {
|
|
40
|
+
block: number;
|
|
41
|
+
count: number;
|
|
42
|
+
};
|
|
43
|
+
listen(streams: StreamToListen | StreamsToListen): Promise<void>;
|
|
44
|
+
addAckMessage(stream: string, id: StreamMessageId): void;
|
|
45
|
+
private listenForStreams;
|
|
46
|
+
private hasStreamState;
|
|
47
|
+
private getStreamState;
|
|
48
|
+
private initStreamState;
|
|
49
|
+
private readStreams;
|
|
50
|
+
private processStreamMessages;
|
|
51
|
+
private acknowlegdeMessages;
|
|
52
|
+
}
|
package/dist/consumer.js
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RedisConsumer = void 0;
|
|
4
|
+
const retry_processor_1 = require("./retry-processor");
|
|
5
|
+
class RedisConsumer {
|
|
6
|
+
client;
|
|
7
|
+
originalClient;
|
|
8
|
+
state;
|
|
9
|
+
retryProcessor;
|
|
10
|
+
successfullMessages = new Map();
|
|
11
|
+
BLOCK;
|
|
12
|
+
COUNT;
|
|
13
|
+
RETRIES;
|
|
14
|
+
constructor(client, options = {}) {
|
|
15
|
+
this.originalClient = client;
|
|
16
|
+
this.client = client.duplicate();
|
|
17
|
+
this.state = {};
|
|
18
|
+
this.COUNT = options.COUNT ?? 1;
|
|
19
|
+
this.BLOCK = options.BLOCK ?? 0;
|
|
20
|
+
this.RETRIES = options.retries ?? 3;
|
|
21
|
+
this.retryProcessor = new retry_processor_1.RetryProcessor(this, {
|
|
22
|
+
retryTime: options.retryTime,
|
|
23
|
+
maxRetry: this.RETRIES,
|
|
24
|
+
});
|
|
25
|
+
this.client.connect();
|
|
26
|
+
}
|
|
27
|
+
set block(block) {
|
|
28
|
+
this.BLOCK = block;
|
|
29
|
+
}
|
|
30
|
+
set count(count) {
|
|
31
|
+
this.COUNT = count;
|
|
32
|
+
}
|
|
33
|
+
set retries(retries) {
|
|
34
|
+
this.RETRIES = retries;
|
|
35
|
+
}
|
|
36
|
+
get settings() {
|
|
37
|
+
return { block: this.BLOCK, count: this.COUNT };
|
|
38
|
+
}
|
|
39
|
+
async listen(streams) {
|
|
40
|
+
if (!Array.isArray(streams)) {
|
|
41
|
+
streams = [streams];
|
|
42
|
+
}
|
|
43
|
+
for (const stream of streams) {
|
|
44
|
+
const groupExists = await this.originalClient.groupExists(stream.name);
|
|
45
|
+
if (!groupExists) {
|
|
46
|
+
await this.originalClient.createGroup(stream.name);
|
|
47
|
+
}
|
|
48
|
+
if (this.hasStreamState(stream.name))
|
|
49
|
+
continue;
|
|
50
|
+
this.initStreamState(stream);
|
|
51
|
+
}
|
|
52
|
+
this.listenForStreams();
|
|
53
|
+
}
|
|
54
|
+
addAckMessage(stream, id) {
|
|
55
|
+
if (this.successfullMessages.has(stream)) {
|
|
56
|
+
const ackMessages = this.successfullMessages.get(stream);
|
|
57
|
+
ackMessages.push(id);
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
this.successfullMessages.set(stream, [id]);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
async listenForStreams() {
|
|
64
|
+
const state = this.state;
|
|
65
|
+
const streamsToListen = [];
|
|
66
|
+
for (const stream in state) {
|
|
67
|
+
streamsToListen.push({ key: stream, id: state[stream].nextId });
|
|
68
|
+
}
|
|
69
|
+
const streamsMessages = await this.readStreams(streamsToListen);
|
|
70
|
+
if (!streamsMessages) {
|
|
71
|
+
await this.acknowlegdeMessages();
|
|
72
|
+
this.listenForStreams();
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
for (const streamMessages of streamsMessages) {
|
|
76
|
+
await this.processStreamMessages(streamMessages);
|
|
77
|
+
}
|
|
78
|
+
this.listenForStreams();
|
|
79
|
+
}
|
|
80
|
+
hasStreamState(name) {
|
|
81
|
+
return !!this.getStreamState(name);
|
|
82
|
+
}
|
|
83
|
+
getStreamState(name) {
|
|
84
|
+
const state = this.state[name];
|
|
85
|
+
if (state) {
|
|
86
|
+
return state;
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
initStreamState(stream) {
|
|
93
|
+
const name = stream.name;
|
|
94
|
+
const executable = stream.executable;
|
|
95
|
+
let lastSuccessId;
|
|
96
|
+
if (stream.id) {
|
|
97
|
+
lastSuccessId = stream.id;
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
lastSuccessId = '0-0';
|
|
101
|
+
}
|
|
102
|
+
let nextId = lastSuccessId;
|
|
103
|
+
this.state[name] = { nextId, lastSuccessId, executable, recovering: true };
|
|
104
|
+
}
|
|
105
|
+
async readStreams(streamsToListen) {
|
|
106
|
+
const messages = await this.client.xReadGroup(this.originalClient.groupName, this.originalClient.clientName, streamsToListen, { BLOCK: this.BLOCK, COUNT: this.COUNT });
|
|
107
|
+
if (!messages)
|
|
108
|
+
return null;
|
|
109
|
+
else
|
|
110
|
+
return messages;
|
|
111
|
+
}
|
|
112
|
+
async processStreamMessages(streamMessages) {
|
|
113
|
+
const stream = streamMessages.name;
|
|
114
|
+
const state = this.getStreamState(stream);
|
|
115
|
+
if (!state)
|
|
116
|
+
throw new Error('No state was found for stream processing of ' + stream);
|
|
117
|
+
const fnc = state.executable;
|
|
118
|
+
const messages = streamMessages.messages;
|
|
119
|
+
for (const message of messages) {
|
|
120
|
+
try {
|
|
121
|
+
await fnc(message, stream);
|
|
122
|
+
this.addAckMessage(stream, message.id);
|
|
123
|
+
}
|
|
124
|
+
catch (err) {
|
|
125
|
+
this.client.emit('process-error', err, { stream, message, retries: 0 });
|
|
126
|
+
if (this.RETRIES === 0)
|
|
127
|
+
continue;
|
|
128
|
+
if (err instanceof Error) {
|
|
129
|
+
this.retryProcessor.add(err, stream, message, fnc);
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
const newErr = new Error(String(err));
|
|
133
|
+
this.retryProcessor.add(newErr, stream, message, fnc);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
await this.acknowlegdeMessages();
|
|
138
|
+
const recovering = state.recovering;
|
|
139
|
+
if (recovering && messages.length === 0) {
|
|
140
|
+
state.nextId = '>';
|
|
141
|
+
state.recovering = false;
|
|
142
|
+
}
|
|
143
|
+
else if (recovering) {
|
|
144
|
+
const lastMessage = messages.slice(-1);
|
|
145
|
+
const lastId = lastMessage[0].id;
|
|
146
|
+
state.nextId = lastId;
|
|
147
|
+
}
|
|
148
|
+
return true;
|
|
149
|
+
}
|
|
150
|
+
async acknowlegdeMessages() {
|
|
151
|
+
for (const item of this.successfullMessages) {
|
|
152
|
+
const stream = item[0];
|
|
153
|
+
const ackMessages = item[1];
|
|
154
|
+
const id = await this.originalClient.xAck(stream, this.originalClient.groupName, ackMessages);
|
|
155
|
+
if (id) {
|
|
156
|
+
this.successfullMessages.delete(stream);
|
|
157
|
+
this.originalClient.xDel(stream, ackMessages);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
exports.RedisConsumer = RedisConsumer;
|
package/dist/helpers.js
ADDED
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { StreamMessageReply } from '@redis/client/dist/lib/commands/generic-transformers';
|
|
2
|
+
import { PropType } from './helpers';
|
|
3
|
+
export * from 'redis';
|
|
4
|
+
export { RedisClient } from './client';
|
|
5
|
+
export * from './consumer';
|
|
6
|
+
export * from './producer';
|
|
7
|
+
export { RetryFailedMessage } from './retry-processor';
|
|
8
|
+
export type StreamMessageId = PropType<StreamMessageReply, 'id'>;
|
|
9
|
+
export type StreamMessageData = PropType<StreamMessageReply, 'message'>;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
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
|
+
exports.RedisClient = void 0;
|
|
18
|
+
__exportStar(require("redis"), exports);
|
|
19
|
+
var client_1 = require("./client");
|
|
20
|
+
Object.defineProperty(exports, "RedisClient", { enumerable: true, get: function () { return client_1.RedisClient; } });
|
|
21
|
+
__exportStar(require("./consumer"), exports);
|
|
22
|
+
__exportStar(require("./producer"), exports);
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { RedisScripts } from 'redis';
|
|
2
|
+
import { StreamMessageData, StreamMessageId } from '.';
|
|
3
|
+
import { RedisClient } from './client';
|
|
4
|
+
export declare class RedisProducer<S extends RedisScripts = RedisScripts> {
|
|
5
|
+
private client;
|
|
6
|
+
constructor(client: RedisClient<S>);
|
|
7
|
+
add(stream: StreamMessageId, message: StreamMessageData): void;
|
|
8
|
+
}
|
package/dist/producer.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RedisProducer = void 0;
|
|
4
|
+
class RedisProducer {
|
|
5
|
+
client;
|
|
6
|
+
constructor(client) {
|
|
7
|
+
this.client = client;
|
|
8
|
+
}
|
|
9
|
+
add(stream, message) {
|
|
10
|
+
this.client.xAdd(stream, '*', message);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
exports.RedisProducer = RedisProducer;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
/// <reference types="node" />
|
|
3
|
+
import { StreamProcessingFunction, RedisConsumer } from './consumer';
|
|
4
|
+
import { StreamMessageReply } from '@redis/client/dist/lib/commands/generic-transformers';
|
|
5
|
+
import { RedisScripts } from 'redis';
|
|
6
|
+
import { EventEmitter } from 'stream';
|
|
7
|
+
interface RetryState {
|
|
8
|
+
lastError: Error;
|
|
9
|
+
timestamps: number[];
|
|
10
|
+
retries: number;
|
|
11
|
+
message: StreamMessageReply;
|
|
12
|
+
stream: string;
|
|
13
|
+
executable: StreamProcessingFunction<any>;
|
|
14
|
+
}
|
|
15
|
+
export type RetryFailedMessage = Omit<RetryState, 'executable' | 'lastError'>;
|
|
16
|
+
export type RetryMessage = Omit<RetryFailedMessage, 'timestamps' | 'lastError'> & {
|
|
17
|
+
timestamp: number;
|
|
18
|
+
};
|
|
19
|
+
interface RetryProcessorOptions {
|
|
20
|
+
maxRetry: number;
|
|
21
|
+
retryTime?: string[];
|
|
22
|
+
}
|
|
23
|
+
export declare class RetryProcessor<S extends RedisScripts = RedisScripts> extends EventEmitter {
|
|
24
|
+
private consumer;
|
|
25
|
+
private state;
|
|
26
|
+
private retryTime;
|
|
27
|
+
private maxRetry;
|
|
28
|
+
constructor(consumer: RedisConsumer<S>, options: RetryProcessorOptions);
|
|
29
|
+
add(error: Error, stream: string, message: StreamMessageReply, executable: StreamProcessingFunction<any>): void;
|
|
30
|
+
private processRetry;
|
|
31
|
+
private calcTimeoutTime;
|
|
32
|
+
private emitRetryFail;
|
|
33
|
+
private emitRetry;
|
|
34
|
+
private emitProcessFailed;
|
|
35
|
+
}
|
|
36
|
+
export {};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RetryProcessor = void 0;
|
|
4
|
+
const helpers_1 = require("./helpers");
|
|
5
|
+
const stream_1 = require("stream");
|
|
6
|
+
class RetryProcessor extends stream_1.EventEmitter {
|
|
7
|
+
consumer;
|
|
8
|
+
state = new Map();
|
|
9
|
+
retryTime;
|
|
10
|
+
maxRetry;
|
|
11
|
+
constructor(consumer, options) {
|
|
12
|
+
super();
|
|
13
|
+
this.consumer = consumer;
|
|
14
|
+
this.retryTime = options.retryTime || ['15s', '1m', '15m'];
|
|
15
|
+
this.maxRetry = options.maxRetry;
|
|
16
|
+
}
|
|
17
|
+
add(error, stream, message, executable) {
|
|
18
|
+
const id = message.id;
|
|
19
|
+
if (this.state.has(id))
|
|
20
|
+
return;
|
|
21
|
+
this.state.set(id, { lastError: error, timestamps: [], retries: 0, message, stream, executable });
|
|
22
|
+
this.processRetry(id);
|
|
23
|
+
}
|
|
24
|
+
async processRetry(id) {
|
|
25
|
+
const stateObj = this.state.get(id);
|
|
26
|
+
if (stateObj.retries >= this.maxRetry) {
|
|
27
|
+
this.state.delete(id);
|
|
28
|
+
this.emitRetryFail(stateObj);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
stateObj.retries++;
|
|
32
|
+
const timestamp = new Date().getTime();
|
|
33
|
+
stateObj.timestamps.push(timestamp);
|
|
34
|
+
const timeoutTime = this.calcTimeoutTime(stateObj);
|
|
35
|
+
await (0, helpers_1.timeout)(timeoutTime);
|
|
36
|
+
const fnc = stateObj.executable;
|
|
37
|
+
const message = stateObj.message;
|
|
38
|
+
try {
|
|
39
|
+
this.emitRetry(stateObj);
|
|
40
|
+
await fnc(message, stateObj.stream);
|
|
41
|
+
this.consumer.addAckMessage(stateObj.stream, id);
|
|
42
|
+
this.state.delete(id);
|
|
43
|
+
}
|
|
44
|
+
catch (err) {
|
|
45
|
+
if (err instanceof Error) {
|
|
46
|
+
stateObj.lastError = err;
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
const newErr = new Error(String(err));
|
|
50
|
+
stateObj.lastError = newErr;
|
|
51
|
+
}
|
|
52
|
+
this.emitProcessFailed(stateObj);
|
|
53
|
+
this.processRetry(id);
|
|
54
|
+
}
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
calcTimeoutTime(stateObj) {
|
|
58
|
+
const retry = stateObj.retries;
|
|
59
|
+
const index = (retry > this.retryTime.length ? this.retryTime.length : retry) - 1;
|
|
60
|
+
const timeString = this.retryTime[index];
|
|
61
|
+
let hours = +timeString.replace(/(\d+)h/, '$1');
|
|
62
|
+
let minutes = +timeString.replace(/(\d+)m/, '$1');
|
|
63
|
+
let seconds = +timeString.replace(/(\d+)s/, '$1');
|
|
64
|
+
if (isNaN(hours))
|
|
65
|
+
hours = 0;
|
|
66
|
+
if (isNaN(minutes))
|
|
67
|
+
minutes = 0;
|
|
68
|
+
if (isNaN(seconds))
|
|
69
|
+
seconds = 0;
|
|
70
|
+
let timeoutTime = hours * 3600 * 1000 + minutes * 60 * 1000 + seconds * 1000;
|
|
71
|
+
return timeoutTime;
|
|
72
|
+
}
|
|
73
|
+
emitRetryFail({ lastError, stream, message, retries, timestamps }) {
|
|
74
|
+
this.consumer.client.emit('retry-failed', lastError, { stream, message, retries, timestamps });
|
|
75
|
+
}
|
|
76
|
+
emitRetry({ stream, message, retries, timestamps }) {
|
|
77
|
+
const timestamp = timestamps[timestamps.length - 1];
|
|
78
|
+
this.consumer.client.emit('retry', { stream, message, retries, timestamp });
|
|
79
|
+
}
|
|
80
|
+
emitProcessFailed({ lastError, stream, message, retries }) {
|
|
81
|
+
this.consumer.client.emit('process-error', lastError, { stream, message, retries });
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
exports.RetryProcessor = RetryProcessor;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "redis-consumer",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.3",
|
|
4
4
|
"description": "Simple NodeJs consumer and producer for Redis Streams",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
},
|
|
34
34
|
"homepage": "https://github.com/tomasky/redis-streams-nodejs#readme",
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"redis": "^4.6.
|
|
36
|
+
"redis": "^4.6.12"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"@types/node": "^18.0.0",
|