dt-common-device 3.0.10 → 3.0.11
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/config/config.d.ts +1 -2
- package/dist/config/config.js +4 -5
- package/dist/device/local/repository/Schedule.repository.d.ts +0 -1
- package/dist/device/local/repository/Schedule.repository.js +6 -6
- package/dist/queue/entities/HybridHttpQueue.d.ts +4 -14
- package/dist/queue/entities/HybridHttpQueue.js +31 -119
- package/dist/queue/interfaces/IHybridHttpQueue.d.ts +2 -12
- package/dist/queue/interfaces/IJobResult.d.ts +1 -8
- package/dist/queue/interfaces/index.d.ts +0 -1
- package/dist/queue/interfaces/index.js +0 -1
- package/dist/queue/services/QueueService.d.ts +2 -12
- package/dist/queue/types/queue.types.d.ts +10 -29
- package/dist/queue/utils/jobUtils.d.ts +0 -3
- package/dist/queue/utils/jobUtils.js +0 -48
- package/dist/queue/utils/queueUtils.d.ts +7 -0
- package/dist/queue/utils/queueUtils.js +113 -4
- package/package.json +6 -1
- package/.eslintrc.js +0 -44
- package/src/alerts/Alert.model.ts +0 -289
- package/src/alerts/Alert.repository.ts +0 -487
- package/src/alerts/Alert.service.ts +0 -711
- package/src/alerts/AlertBuilder.example.ts +0 -126
- package/src/alerts/AlertBuilder.ts +0 -208
- package/src/alerts/AlertService.example.ts +0 -232
- package/src/alerts/alert.types.ts +0 -64
- package/src/alerts/index.ts +0 -3
- package/src/config/config.ts +0 -202
- package/src/config/config.types.ts +0 -21
- package/src/connection/Connection.repository.ts +0 -52
- package/src/connection/Connection.service.ts +0 -39
- package/src/connection/IConnection.ts +0 -27
- package/src/connection/index.ts +0 -3
- package/src/constants/ConnectionProviders.ts +0 -11
- package/src/constants/Event.ts +0 -89
- package/src/constants/Service.ts +0 -17
- package/src/constants/index.ts +0 -3
- package/src/db/db.ts +0 -24
- package/src/db/index.ts +0 -2
- package/src/db/redis.ts +0 -20
- package/src/device/cloud/entities/CloudDevice.ts +0 -40
- package/src/device/cloud/entities/CloudDeviceService.ts +0 -8
- package/src/device/cloud/entities/DeviceFactory.ts +0 -27
- package/src/device/cloud/entities/index.ts +0 -3
- package/src/device/cloud/interfaces/ICloudDevice.ts +0 -14
- package/src/device/cloud/interfaces/ICloudDeviceService.ts +0 -6
- package/src/device/cloud/interfaces/IDeviceFactory.ts +0 -5
- package/src/device/cloud/interfaces/IRawDataTransformer.ts +0 -5
- package/src/device/cloud/interfaces/IRawDevice.ts +0 -19
- package/src/device/cloud/interfaces/index.ts +0 -5
- package/src/device/local/interfaces/IDevice.ts +0 -62
- package/src/device/local/interfaces/IDtDevice.ts +0 -16
- package/src/device/local/interfaces/ISchedule.ts +0 -40
- package/src/device/local/interfaces/index.ts +0 -3
- package/src/device/local/repository/Device.repository.ts +0 -368
- package/src/device/local/repository/Hub.repository.ts +0 -107
- package/src/device/local/repository/Schedule.repository.ts +0 -72
- package/src/device/local/services/Device.service.ts +0 -436
- package/src/device/local/services/Hub.service.ts +0 -57
- package/src/device/local/services/Schedule.service.ts +0 -26
- package/src/device/local/services/index.ts +0 -3
- package/src/docs/Alert.model.md +0 -319
- package/src/docs/Alerts&IssuesModel.md +0 -312
- package/src/docs/Issue.model.md +0 -386
- package/src/docs/SECURITY.md +0 -67
- package/src/docs/TROUBLESHOOTING.md +0 -184
- package/src/events/BaseEventHandler.ts +0 -145
- package/src/events/BaseEventTransformer.ts +0 -97
- package/src/events/DeviceEventHandler.ts +0 -213
- package/src/events/DeviceEventTransformerFactory.ts +0 -77
- package/src/events/EventHandler.ts +0 -124
- package/src/events/EventHandlerOrchestrator.ts +0 -119
- package/src/events/EventProcessingService.ts +0 -248
- package/src/events/InternalEventSubscription.ts +0 -194
- package/src/events/index.ts +0 -9
- package/src/events/interfaces/DeviceEvent.ts +0 -56
- package/src/events/interfaces/IEventHandler.ts +0 -28
- package/src/events/interfaces/IEventTransformer.ts +0 -8
- package/src/events/interfaces/IInternalEvent.ts +0 -33
- package/src/events/interfaces/index.ts +0 -4
- package/src/index.ts +0 -43
- package/src/issues/Issue.model.ts +0 -350
- package/src/issues/Issue.repository.ts +0 -517
- package/src/issues/Issue.service.ts +0 -932
- package/src/issues/IssueBuilder.example.ts +0 -210
- package/src/issues/IssueBuilder.ts +0 -263
- package/src/issues/IssueService.example.ts +0 -310
- package/src/issues/index.ts +0 -2
- package/src/issues/issue.types.ts +0 -98
- package/src/property/IProperty.ts +0 -30
- package/src/property/Property.repository.ts +0 -53
- package/src/property/Property.service.ts +0 -38
- package/src/property/index.ts +0 -2
- package/src/queue/entities/HybridHttpQueue.ts +0 -274
- package/src/queue/entities/index.ts +0 -1
- package/src/queue/index.ts +0 -6
- package/src/queue/interfaces/IHttpRequestJob.ts +0 -10
- package/src/queue/interfaces/IHybridHttpQueue.ts +0 -25
- package/src/queue/interfaces/IJobResult.ts +0 -15
- package/src/queue/interfaces/IRateLimitConfig.ts +0 -5
- package/src/queue/interfaces/index.ts +0 -4
- package/src/queue/services/QueueService.ts +0 -40
- package/src/queue/services/index.ts +0 -1
- package/src/queue/types/http.types.ts +0 -23
- package/src/queue/types/index.ts +0 -2
- package/src/queue/types/queue.types.ts +0 -21
- package/src/queue/utils/index.ts +0 -3
- package/src/queue/utils/jobUtils.ts +0 -79
- package/src/queue/utils/queueUtils.ts +0 -84
- package/src/queue/utils/rateLimit.utils.ts +0 -131
- package/src/utils/http.utils.ts +0 -143
- package/src/utils/index.ts +0 -2
- package/src/utils/redis.utils.ts +0 -74
- package/tsconfig.json +0 -20
package/dist/config/config.d.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { InternalEventSubscription } from "../events";
|
|
2
|
-
import { IConfig
|
|
2
|
+
import { IConfig } from "./config.types";
|
|
3
3
|
export declare function initialize(cfg: IConfig): Promise<void>;
|
|
4
4
|
export declare function getConfig(): IConfig;
|
|
5
|
-
export declare function getLogger(): ILogger;
|
|
6
5
|
export declare function getEventSubscription(): InternalEventSubscription | null;
|
|
7
6
|
export declare function checkRequiredEnv(): void;
|
|
8
7
|
export declare function ensureAuditInitialized(): void;
|
package/dist/config/config.js
CHANGED
|
@@ -5,7 +5,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.initialize = initialize;
|
|
7
7
|
exports.getConfig = getConfig;
|
|
8
|
-
exports.getLogger = getLogger;
|
|
9
8
|
exports.getEventSubscription = getEventSubscription;
|
|
10
9
|
exports.checkRequiredEnv = checkRequiredEnv;
|
|
11
10
|
exports.ensureAuditInitialized = ensureAuditInitialized;
|
|
@@ -83,10 +82,6 @@ function getConfig() {
|
|
|
83
82
|
}
|
|
84
83
|
return config;
|
|
85
84
|
}
|
|
86
|
-
// Direct logger export for easier usage
|
|
87
|
-
function getLogger() {
|
|
88
|
-
return getConfig().LOGGER;
|
|
89
|
-
}
|
|
90
85
|
function getEventSubscription() {
|
|
91
86
|
return eventSubscription;
|
|
92
87
|
}
|
|
@@ -120,6 +115,10 @@ function ensureAuditInitialized() {
|
|
|
120
115
|
(0, dt_audit_library_1.initializeAudit)(apiKey, host);
|
|
121
116
|
auditInitialized = true;
|
|
122
117
|
}
|
|
118
|
+
// // Direct logger export for easier usage
|
|
119
|
+
// export function getLogger(): ILogger {
|
|
120
|
+
// return getConfig().LOGGER;
|
|
121
|
+
// }
|
|
123
122
|
/**
|
|
124
123
|
* Returns the PostgreSQL DB URI from environment variables.
|
|
125
124
|
* Throws an error if not set.
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { ISchedule } from "../interfaces/ISchedule";
|
|
2
2
|
export declare class ScheduleRepository {
|
|
3
3
|
private readonly axiosInstance;
|
|
4
|
-
private readonly logger;
|
|
5
4
|
constructor();
|
|
6
5
|
getSchedule(scheduleId: string): Promise<any>;
|
|
7
6
|
getScheduleByZone(zoneId: string): Promise<any>;
|
|
@@ -40,16 +40,16 @@ var __setFunctionName = (this && this.__setFunctionName) || function (f, name, p
|
|
|
40
40
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
41
41
|
exports.ScheduleRepository = void 0;
|
|
42
42
|
const typedi_1 = require("typedi");
|
|
43
|
-
const config_1 = require("../../../config/config");
|
|
44
43
|
const http_utils_1 = require("../../../utils/http.utils");
|
|
44
|
+
const config_1 = require("../../../config/config");
|
|
45
45
|
let ScheduleRepository = (() => {
|
|
46
46
|
let _classDecorators = [(0, typedi_1.Service)()];
|
|
47
47
|
let _classDescriptor;
|
|
48
48
|
let _classExtraInitializers = [];
|
|
49
49
|
let _classThis;
|
|
50
50
|
var ScheduleRepository = _classThis = class {
|
|
51
|
+
// private readonly logger = getLogger();
|
|
51
52
|
constructor() {
|
|
52
|
-
this.logger = (0, config_1.getLogger)();
|
|
53
53
|
this.axiosInstance = (0, http_utils_1.getDeviceServiceAxiosInstance)();
|
|
54
54
|
}
|
|
55
55
|
async getSchedule(scheduleId) {
|
|
@@ -58,7 +58,7 @@ let ScheduleRepository = (() => {
|
|
|
58
58
|
return response.data;
|
|
59
59
|
}
|
|
60
60
|
catch (error) {
|
|
61
|
-
|
|
61
|
+
(0, config_1.getConfig)().LOGGER.error(`Failed to get schedule ${scheduleId}:`, error);
|
|
62
62
|
const errorMessage = error.response?.data?.message || error.message || "Unknown error";
|
|
63
63
|
throw new Error(`Failed to get schedule: ${errorMessage}`);
|
|
64
64
|
}
|
|
@@ -69,7 +69,7 @@ let ScheduleRepository = (() => {
|
|
|
69
69
|
return response.data;
|
|
70
70
|
}
|
|
71
71
|
catch (error) {
|
|
72
|
-
|
|
72
|
+
(0, config_1.getConfig)().LOGGER.error(`Failed to get schedule by zone ${zoneId}:`, error);
|
|
73
73
|
const errorMessage = error.response?.data?.message || error.message || "Unknown error";
|
|
74
74
|
throw new Error(`Failed to get schedule: ${errorMessage}`);
|
|
75
75
|
}
|
|
@@ -80,7 +80,7 @@ let ScheduleRepository = (() => {
|
|
|
80
80
|
return response.data;
|
|
81
81
|
}
|
|
82
82
|
catch (error) {
|
|
83
|
-
|
|
83
|
+
(0, config_1.getConfig)().LOGGER.error(`Failed to update schedule ${scheduleId}:`, error);
|
|
84
84
|
const errorMessage = error.response?.data?.message || error.message || "Unknown error";
|
|
85
85
|
throw new Error(`Failed to update schedule: ${errorMessage}`);
|
|
86
86
|
}
|
|
@@ -91,7 +91,7 @@ let ScheduleRepository = (() => {
|
|
|
91
91
|
return response.data;
|
|
92
92
|
}
|
|
93
93
|
catch (error) {
|
|
94
|
-
|
|
94
|
+
(0, config_1.getConfig)().LOGGER.error(`Failed to delete schedule from DB ${scheduleId}:`, error);
|
|
95
95
|
throw new Error(`Failed to delete schedule from DB: ${error.message}`);
|
|
96
96
|
}
|
|
97
97
|
}
|
|
@@ -1,25 +1,15 @@
|
|
|
1
1
|
import { HttpCallOption } from "../types/http.types";
|
|
2
2
|
import { IQueueResponse } from "../interfaces";
|
|
3
|
+
import { RequestQueueOptions } from "../types/queue.types";
|
|
3
4
|
export declare class HybridHttpQueue {
|
|
5
|
+
private readonly rateLimitConfigs;
|
|
4
6
|
private readonly queues;
|
|
5
7
|
private readonly workers;
|
|
6
|
-
private readonly rateLimitConfigs;
|
|
7
8
|
private readonly jobResults;
|
|
8
9
|
constructor();
|
|
9
|
-
private
|
|
10
|
+
private addToQueue;
|
|
10
11
|
private processHttpRequest;
|
|
11
|
-
request(options:
|
|
12
|
-
method: string;
|
|
13
|
-
url: string;
|
|
14
|
-
body?: any;
|
|
15
|
-
params?: Record<string, any>;
|
|
16
|
-
headers?: Record<string, string>;
|
|
17
|
-
queueOptions?: {
|
|
18
|
-
connectionId: string;
|
|
19
|
-
connectionProvider: string;
|
|
20
|
-
microservice: string;
|
|
21
|
-
};
|
|
22
|
-
}): Promise<IQueueResponse>;
|
|
12
|
+
request(options: RequestQueueOptions): Promise<any>;
|
|
23
13
|
handleRequest(url: string, method: string, options: HttpCallOption): Promise<IQueueResponse>;
|
|
24
14
|
shutdown(): Promise<void>;
|
|
25
15
|
}
|
|
@@ -37,18 +37,13 @@ var __setFunctionName = (this && this.__setFunctionName) || function (f, name, p
|
|
|
37
37
|
if (typeof name === "symbol") name = name.description ? "[".concat(name.description, "]") : "";
|
|
38
38
|
return Object.defineProperty(f, "name", { configurable: true, value: prefix ? "".concat(prefix, " ", name) : name });
|
|
39
39
|
};
|
|
40
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
41
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
42
|
-
};
|
|
43
40
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
44
41
|
exports.HybridHttpQueue = void 0;
|
|
45
|
-
const config_1 = require("../../config/config");
|
|
46
|
-
const axios_1 = __importDefault(require("axios"));
|
|
47
|
-
const dt_audit_library_1 = require("dt-audit-library");
|
|
48
42
|
const typedi_1 = require("typedi");
|
|
49
43
|
const rateLimit_utils_1 = require("../utils/rateLimit.utils");
|
|
50
44
|
const jobUtils_1 = require("../utils/jobUtils");
|
|
51
45
|
const queueUtils_1 = require("../utils/queueUtils");
|
|
46
|
+
const config_1 = require("../../config/config");
|
|
52
47
|
let HybridHttpQueue = (() => {
|
|
53
48
|
let _classDecorators = [(0, typedi_1.Service)()];
|
|
54
49
|
let _classDescriptor;
|
|
@@ -56,13 +51,15 @@ let HybridHttpQueue = (() => {
|
|
|
56
51
|
let _classThis;
|
|
57
52
|
var HybridHttpQueue = _classThis = class {
|
|
58
53
|
constructor() {
|
|
54
|
+
// BullMQ queues and workers for persistent storage
|
|
59
55
|
this.queues = new Map();
|
|
60
56
|
this.workers = new Map();
|
|
61
57
|
this.jobResults = new Map();
|
|
62
58
|
this.rateLimitConfigs = rateLimit_utils_1.RateLimitUtils.initializeRateLimitConfigs();
|
|
63
59
|
}
|
|
64
|
-
async
|
|
65
|
-
const
|
|
60
|
+
async addToQueue(connectionId, provider, url, method, options) {
|
|
61
|
+
const queueKey = queueUtils_1.QueueUtils.getRequestQueueKey(connectionId, provider);
|
|
62
|
+
// Calculate delay based on rate limit window
|
|
66
63
|
const key = `rate_limit:${provider}:${connectionId}`;
|
|
67
64
|
const config = this.rateLimitConfigs.get(provider);
|
|
68
65
|
const windowMs = config?.windowMs ?? 60000;
|
|
@@ -70,11 +67,14 @@ let HybridHttpQueue = (() => {
|
|
|
70
67
|
const now = Date.now();
|
|
71
68
|
const windowStart = now - windowMs;
|
|
72
69
|
const recentRequests = timestamps.filter((t) => t > windowStart);
|
|
73
|
-
|
|
74
|
-
|
|
70
|
+
let delay = 0;
|
|
71
|
+
if (recentRequests.length >= (config?.maxRequests ?? 5)) {
|
|
72
|
+
const earliestRequest = recentRequests[0];
|
|
73
|
+
const nextAvailableTime = earliestRequest + windowMs;
|
|
74
|
+
delay = Math.max(nextAvailableTime - now, 1000); // At least 1s delay
|
|
75
|
+
}
|
|
75
76
|
// Create job data
|
|
76
77
|
const jobData = {
|
|
77
|
-
microservice,
|
|
78
78
|
connectionId,
|
|
79
79
|
provider,
|
|
80
80
|
url,
|
|
@@ -82,78 +82,25 @@ let HybridHttpQueue = (() => {
|
|
|
82
82
|
options,
|
|
83
83
|
timestamp: Date.now(),
|
|
84
84
|
};
|
|
85
|
-
// Add job to queue with delay
|
|
86
|
-
const
|
|
87
|
-
|
|
85
|
+
// Add job to BullMQ queue with delay
|
|
86
|
+
const jobId = await queueUtils_1.QueueUtils.addJobToQueue(queueKey, jobData, delay, this.queues);
|
|
87
|
+
// Initialize worker if not exists
|
|
88
88
|
queueUtils_1.QueueUtils.getOrCreateWorker(queueKey, this.workers, this.processHttpRequest.bind(this), this.jobResults);
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
removeOnComplete: { age: 300, count: 1 },
|
|
93
|
-
removeOnFail: { age: 300, count: 1 },
|
|
94
|
-
});
|
|
95
|
-
await (0, dt_audit_library_1.publishAudit)({
|
|
96
|
-
eventType: "http.request.rateLimitQueued",
|
|
97
|
-
properties: {
|
|
98
|
-
resource: microservice,
|
|
99
|
-
connectionId,
|
|
100
|
-
provider,
|
|
101
|
-
endpoint: url,
|
|
102
|
-
method,
|
|
103
|
-
timestamp: Date.now(),
|
|
104
|
-
queueId: job.id,
|
|
105
|
-
reason: "rate_limit_exceeded_queued",
|
|
106
|
-
delay,
|
|
107
|
-
estimatedProcessingTime: now + delay,
|
|
108
|
-
},
|
|
109
|
-
});
|
|
110
|
-
// Return immediate response to controller
|
|
111
|
-
return {
|
|
112
|
-
success: true,
|
|
113
|
-
queued: true,
|
|
114
|
-
estimatedProcessingTime: now + delay,
|
|
115
|
-
jobId: job.id,
|
|
116
|
-
};
|
|
89
|
+
(0, config_1.getConfig)().LOGGER.info(`Request queued: ${method} ${url} -> ${provider} [${connectionId}]. Job ID: ${jobId}, Delay: ${delay}ms`);
|
|
90
|
+
// Wait for job completion and return result
|
|
91
|
+
return queueUtils_1.QueueUtils.waitForJobCompletion(jobId, queueKey, this.jobResults);
|
|
117
92
|
}
|
|
118
93
|
async processHttpRequest(job) {
|
|
119
94
|
const { connectionId, provider, url, method, options } = job.data;
|
|
95
|
+
// Check rate limit before processing
|
|
120
96
|
const allowed = await rateLimit_utils_1.RateLimitUtils.isRateLimitAllowed(connectionId, provider, this.rateLimitConfigs);
|
|
121
97
|
if (!allowed) {
|
|
122
|
-
// This shouldn't happen since we
|
|
123
|
-
(0, config_1.getConfig)().LOGGER.warn(`Job ${job.id} still rate limited after delay,
|
|
124
|
-
|
|
125
|
-
}
|
|
126
|
-
await rateLimit_utils_1.RateLimitUtils.recordRequest(connectionId, provider);
|
|
127
|
-
try {
|
|
128
|
-
(0, config_1.getConfig)().LOGGER.info(`Executing HTTP request: ${method} ${url} for ${provider}`);
|
|
129
|
-
const response = await (0, axios_1.default)({
|
|
130
|
-
method: method.toLowerCase(),
|
|
131
|
-
url: url,
|
|
132
|
-
headers: options.headers || {},
|
|
133
|
-
timeout: 30000,
|
|
134
|
-
...(options.body && { data: options.body }),
|
|
135
|
-
...(options.params && { params: options.params }),
|
|
136
|
-
});
|
|
137
|
-
(0, config_1.getConfig)().LOGGER.info(`HTTP request successful: ${method} ${url} for ${provider}`);
|
|
138
|
-
return response.data;
|
|
139
|
-
}
|
|
140
|
-
catch (error) {
|
|
141
|
-
(0, config_1.getConfig)().LOGGER.error(`HTTP request failed ${job.id}: ${error.message}`);
|
|
142
|
-
await (0, dt_audit_library_1.publishAudit)({
|
|
143
|
-
eventType: "http.request.error",
|
|
144
|
-
properties: {
|
|
145
|
-
connectionId,
|
|
146
|
-
provider,
|
|
147
|
-
endpoint: url,
|
|
148
|
-
method,
|
|
149
|
-
timestamp: Date.now(),
|
|
150
|
-
queueId: job.id,
|
|
151
|
-
reason: "execution_error",
|
|
152
|
-
errorMessage: error.message,
|
|
153
|
-
},
|
|
154
|
-
});
|
|
155
|
-
throw new Error(`HTTP request failed: ${error.message}`);
|
|
98
|
+
// This shouldn't happen since we calculate delay, but handle it gracefully
|
|
99
|
+
(0, config_1.getConfig)().LOGGER.warn(`Job ${job.id} still rate limited after delay, waiting for window to expire...`);
|
|
100
|
+
await queueUtils_1.QueueUtils.waitForRateLimitExpiry(connectionId, provider, this.rateLimitConfigs);
|
|
156
101
|
}
|
|
102
|
+
// Execute the HTTP request
|
|
103
|
+
return queueUtils_1.QueueUtils.executeHttpRequest(url, method, options, connectionId, provider);
|
|
157
104
|
}
|
|
158
105
|
async request(options) {
|
|
159
106
|
const { method, url, body, params, headers, queueOptions } = options;
|
|
@@ -171,50 +118,15 @@ let HybridHttpQueue = (() => {
|
|
|
171
118
|
const { connectionId, provider, microservice } = jobUtils_1.JobUtils.extractConnectionDetails(options);
|
|
172
119
|
// Check rate limit first
|
|
173
120
|
const allowed = await rateLimit_utils_1.RateLimitUtils.isRateLimitAllowed(connectionId, provider, this.rateLimitConfigs);
|
|
174
|
-
if (
|
|
175
|
-
// Rate
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
// Not rate limited - process immediately
|
|
179
|
-
(0, config_1.getConfig)().LOGGER.info(`Processing immediately: ${method} ${url} -> ${provider} [${connectionId}]`);
|
|
180
|
-
try {
|
|
181
|
-
// Record the request first
|
|
182
|
-
await rateLimit_utils_1.RateLimitUtils.recordRequest(connectionId, provider);
|
|
183
|
-
// Execute the HTTP request
|
|
184
|
-
const response = await (0, axios_1.default)({
|
|
185
|
-
method: method.toLowerCase(),
|
|
186
|
-
url: url,
|
|
187
|
-
headers: options.headers || {},
|
|
188
|
-
timeout: 30000,
|
|
189
|
-
...(options.body && { data: options.body }),
|
|
190
|
-
...(options.params && { params: options.params }),
|
|
191
|
-
});
|
|
192
|
-
(0, config_1.getConfig)().LOGGER.info(`HTTP request successful: ${method} ${url} for ${provider}`);
|
|
193
|
-
return {
|
|
194
|
-
success: true,
|
|
195
|
-
data: response.data,
|
|
196
|
-
queued: false,
|
|
197
|
-
};
|
|
121
|
+
if (allowed) {
|
|
122
|
+
// Rate limit not exceeded - execute immediately
|
|
123
|
+
(0, config_1.getConfig)().LOGGER.info(`Rate limit not exceeded: ${method} ${url} -> ${provider} [${connectionId}], executing immediately`);
|
|
124
|
+
return queueUtils_1.QueueUtils.executeHttpRequest(url, method, options, connectionId, provider);
|
|
198
125
|
}
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
properties: {
|
|
204
|
-
connectionId,
|
|
205
|
-
provider,
|
|
206
|
-
endpoint: url,
|
|
207
|
-
method,
|
|
208
|
-
timestamp: Date.now(),
|
|
209
|
-
reason: "execution_error",
|
|
210
|
-
errorMessage: error.message,
|
|
211
|
-
},
|
|
212
|
-
});
|
|
213
|
-
return {
|
|
214
|
-
success: false,
|
|
215
|
-
error: `HTTP request failed: ${error.message}`,
|
|
216
|
-
queued: false,
|
|
217
|
-
};
|
|
126
|
+
else {
|
|
127
|
+
// Rate limit exceeded - add to BullMQ queue
|
|
128
|
+
(0, config_1.getConfig)().LOGGER.info(`Rate limit exceeded: ${method} ${url} -> ${provider} [${connectionId}], adding to BullMQ queue`);
|
|
129
|
+
return this.addToQueue(connectionId, provider, url, method, options);
|
|
218
130
|
}
|
|
219
131
|
}
|
|
220
132
|
async shutdown() {
|
|
@@ -1,18 +1,8 @@
|
|
|
1
1
|
import { HttpCallOption } from "../types/http.types";
|
|
2
2
|
import { IQueueResponse } from "./IJobResult";
|
|
3
|
+
import { RequestQueueOptions } from "../types/queue.types";
|
|
3
4
|
export interface IHybridHttpQueue {
|
|
4
|
-
request(options:
|
|
5
|
-
method: string;
|
|
6
|
-
url: string;
|
|
7
|
-
body?: any;
|
|
8
|
-
params?: Record<string, any>;
|
|
9
|
-
headers?: Record<string, string>;
|
|
10
|
-
queueOptions?: {
|
|
11
|
-
connectionId: string;
|
|
12
|
-
connectionProvider: string;
|
|
13
|
-
microservice: string;
|
|
14
|
-
};
|
|
15
|
-
}): Promise<IQueueResponse>;
|
|
5
|
+
request(options: RequestQueueOptions): Promise<IQueueResponse>;
|
|
16
6
|
handleRequest(url: string, method: string, options: HttpCallOption): Promise<IQueueResponse>;
|
|
17
7
|
shutdown(): Promise<void>;
|
|
18
8
|
}
|
|
@@ -4,11 +4,4 @@ export interface IJobResult {
|
|
|
4
4
|
resolved: boolean;
|
|
5
5
|
timestamp: number;
|
|
6
6
|
}
|
|
7
|
-
export
|
|
8
|
-
success: boolean;
|
|
9
|
-
data?: any;
|
|
10
|
-
error?: string;
|
|
11
|
-
queued?: boolean;
|
|
12
|
-
estimatedProcessingTime?: number;
|
|
13
|
-
jobId?: string;
|
|
14
|
-
}
|
|
7
|
+
export type IQueueResponse = any;
|
|
@@ -15,6 +15,5 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
__exportStar(require("./IHybridHttpQueue"), exports);
|
|
18
|
-
__exportStar(require("./IHttpRequestJob"), exports);
|
|
19
18
|
__exportStar(require("./IJobResult"), exports);
|
|
20
19
|
__exportStar(require("./IRateLimitConfig"), exports);
|
|
@@ -1,20 +1,10 @@
|
|
|
1
1
|
import { IHybridHttpQueue, IQueueResponse } from "../interfaces";
|
|
2
2
|
import { HttpCallOption } from "../types/http.types";
|
|
3
|
+
import { RequestQueueOptions } from "../types/queue.types";
|
|
3
4
|
export declare class QueueService implements IHybridHttpQueue {
|
|
4
5
|
private readonly hybridQueue;
|
|
5
6
|
constructor();
|
|
6
|
-
request(options:
|
|
7
|
-
method: string;
|
|
8
|
-
url: string;
|
|
9
|
-
body?: any;
|
|
10
|
-
params?: Record<string, any>;
|
|
11
|
-
headers?: Record<string, string>;
|
|
12
|
-
queueOptions?: {
|
|
13
|
-
connectionId: string;
|
|
14
|
-
connectionProvider: string;
|
|
15
|
-
microservice: string;
|
|
16
|
-
};
|
|
17
|
-
}): Promise<IQueueResponse>;
|
|
7
|
+
request(options: RequestQueueOptions): Promise<IQueueResponse>;
|
|
18
8
|
handleRequest(url: string, method: string, options: HttpCallOption): Promise<IQueueResponse>;
|
|
19
9
|
shutdown(): Promise<void>;
|
|
20
10
|
}
|
|
@@ -1,31 +1,12 @@
|
|
|
1
|
-
export interface
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
export interface RequestQueueOptions {
|
|
2
|
+
method: string;
|
|
3
|
+
url: string;
|
|
4
|
+
body?: any;
|
|
5
|
+
params?: Record<string, any>;
|
|
6
|
+
headers?: Record<string, string>;
|
|
7
|
+
queueOptions?: {
|
|
8
|
+
connectionId: string;
|
|
9
|
+
connectionProvider: string;
|
|
10
|
+
microservice: string;
|
|
6
11
|
};
|
|
7
|
-
removeOnFail: {
|
|
8
|
-
age: number;
|
|
9
|
-
count: number;
|
|
10
|
-
};
|
|
11
|
-
lockDuration: number;
|
|
12
|
-
stalledInterval: number;
|
|
13
|
-
}
|
|
14
|
-
export interface JobOptions {
|
|
15
|
-
attempts: number;
|
|
16
|
-
removeOnComplete: {
|
|
17
|
-
age: number;
|
|
18
|
-
count: number;
|
|
19
|
-
};
|
|
20
|
-
removeOnFail: {
|
|
21
|
-
age: number;
|
|
22
|
-
count: number;
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
export interface QueueMetrics {
|
|
26
|
-
totalJobs: number;
|
|
27
|
-
completedJobs: number;
|
|
28
|
-
failedJobs: number;
|
|
29
|
-
pendingJobs: number;
|
|
30
|
-
activeJobs: number;
|
|
31
12
|
}
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
import { Job } from "bullmq";
|
|
2
|
-
import { IJobResult } from "../interfaces";
|
|
3
1
|
export declare class JobUtils {
|
|
4
|
-
static waitForJobCompletion(job: Job, queueKey: string, jobResults: Map<string, IJobResult>): Promise<any>;
|
|
5
2
|
static extractConnectionDetails(options: any): {
|
|
6
3
|
connectionId: string;
|
|
7
4
|
provider: string;
|
|
@@ -2,54 +2,6 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.JobUtils = void 0;
|
|
4
4
|
class JobUtils {
|
|
5
|
-
static async waitForJobCompletion(job, queueKey, jobResults) {
|
|
6
|
-
return new Promise((resolve, reject) => {
|
|
7
|
-
let timeoutId;
|
|
8
|
-
let checkCount = 0;
|
|
9
|
-
const maxChecks = 600;
|
|
10
|
-
const checkJob = async () => {
|
|
11
|
-
if (++checkCount >= maxChecks) {
|
|
12
|
-
clearTimeout(timeoutId);
|
|
13
|
-
return reject(new Error("Job timeout: Request took too long"));
|
|
14
|
-
}
|
|
15
|
-
try {
|
|
16
|
-
const state = await job.getState();
|
|
17
|
-
if (state === "completed") {
|
|
18
|
-
clearTimeout(timeoutId);
|
|
19
|
-
const memoryResult = jobResults.get(job.id);
|
|
20
|
-
if (memoryResult?.resolved) {
|
|
21
|
-
return memoryResult.result !== undefined
|
|
22
|
-
? resolve(memoryResult.result)
|
|
23
|
-
: reject(new Error(memoryResult.error || "Unknown error"));
|
|
24
|
-
}
|
|
25
|
-
// Fallback to job result
|
|
26
|
-
resolve(await job.returnvalue);
|
|
27
|
-
}
|
|
28
|
-
else if (state === "failed") {
|
|
29
|
-
clearTimeout(timeoutId);
|
|
30
|
-
const memoryResult = jobResults.get(job.id);
|
|
31
|
-
const errorMsg = memoryResult?.error ||
|
|
32
|
-
(await job.failedReason) ||
|
|
33
|
-
"Unknown error";
|
|
34
|
-
reject(new Error(`Job failed: ${errorMsg}`));
|
|
35
|
-
}
|
|
36
|
-
else {
|
|
37
|
-
timeoutId = setTimeout(checkJob, checkCount < 10 ? 50 : 100);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
catch (error) {
|
|
41
|
-
clearTimeout(timeoutId);
|
|
42
|
-
reject(new Error(`Error checking job: ${error.message}`));
|
|
43
|
-
}
|
|
44
|
-
};
|
|
45
|
-
checkJob();
|
|
46
|
-
// Backup timeout
|
|
47
|
-
setTimeout(() => {
|
|
48
|
-
clearTimeout(timeoutId);
|
|
49
|
-
reject(new Error("Request timeout: Maximum wait time exceeded"));
|
|
50
|
-
}, 60000);
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
5
|
static extractConnectionDetails(options) {
|
|
54
6
|
const { connectionId, connectionProvider: provider, microservice, } = options?.queueOptions ?? {};
|
|
55
7
|
if (!connectionId)
|
|
@@ -1,5 +1,12 @@
|
|
|
1
|
+
import { HttpCallOption } from "../types/http.types";
|
|
2
|
+
import { IRateLimitConfig } from "../interfaces";
|
|
1
3
|
export declare class QueueUtils {
|
|
2
4
|
static getQueueKey(microservice: string, connectionId: string, provider: string): string;
|
|
5
|
+
static getRequestQueueKey(connectionId: string, provider: string): string;
|
|
3
6
|
static getOrCreateQueue(queueKey: string, queues: Map<string, any>): any;
|
|
4
7
|
static getOrCreateWorker(queueKey: string, workers: Map<string, any>, processFunction: (job: any) => Promise<any>, jobResults: Map<string, any>): void;
|
|
8
|
+
static waitForRateLimitExpiry(connectionId: string, provider: string, rateLimitConfigs: Map<string, IRateLimitConfig>): Promise<void>;
|
|
9
|
+
static executeHttpRequest(url: string, method: string, options: HttpCallOption, connectionId: string, provider: string): Promise<any>;
|
|
10
|
+
static addJobToQueue(queueKey: string, jobData: any, delay: number, queues: Map<string, any>): Promise<string>;
|
|
11
|
+
static waitForJobCompletion(jobId: string, queueKey: string, jobResults: Map<string, any>): Promise<any>;
|
|
5
12
|
}
|