@queuedash/sdk 0.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.md +163 -0
- package/dist/client.d.ts +37 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +205 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/integrations/bee.d.ts +8 -0
- package/dist/integrations/bee.d.ts.map +1 -0
- package/dist/integrations/bee.js +43 -0
- package/dist/integrations/bull.d.ts +8 -0
- package/dist/integrations/bull.d.ts.map +1 -0
- package/dist/integrations/bull.js +45 -0
- package/dist/integrations/bullmq.d.ts +8 -0
- package/dist/integrations/bullmq.d.ts.map +1 -0
- package/dist/integrations/bullmq.js +46 -0
- package/dist/types.d.ts +35 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/package.json +44 -0
package/README.md
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# @queuedash/sdk
|
|
2
|
+
|
|
3
|
+
Official SDK for QueueDash - Real-time monitoring for Bull, BullMQ, and Bee-Queue.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @queuedash/sdk
|
|
9
|
+
# or
|
|
10
|
+
pnpm add @queuedash/sdk
|
|
11
|
+
# or
|
|
12
|
+
yarn add @queuedash/sdk
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Quick Start
|
|
16
|
+
|
|
17
|
+
### BullMQ
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import { Queue } from "bullmq";
|
|
21
|
+
import { QueueDashClient, attachToBullMQ } from "@queuedash/sdk";
|
|
22
|
+
|
|
23
|
+
// Create your queue
|
|
24
|
+
const myQueue = new Queue("my-queue", {
|
|
25
|
+
connection: { host: "localhost", port: 6379 },
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
// Initialize QueueDash client
|
|
29
|
+
const queueDash = new QueueDashClient({
|
|
30
|
+
apiKey: process.env.QUEUEDASH_API_KEY,
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// Attach to your queue - that's it!
|
|
34
|
+
attachToBullMQ(myQueue, queueDash);
|
|
35
|
+
|
|
36
|
+
// Jobs are now automatically synced to QueueDash
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Bull
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
import Queue from "bull";
|
|
43
|
+
import { QueueDashClient, attachToBull } from "@queuedash/sdk";
|
|
44
|
+
|
|
45
|
+
const myQueue = new Queue("my-queue", {
|
|
46
|
+
redis: { host: "localhost", port: 6379 },
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
const queueDash = new QueueDashClient({
|
|
50
|
+
apiKey: process.env.QUEUEDASH_API_KEY,
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
attachToBull(myQueue, queueDash);
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Bee-Queue
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
import Queue from "bee-queue";
|
|
60
|
+
import { QueueDashClient, attachToBeeQueue } from "@queuedash/sdk";
|
|
61
|
+
|
|
62
|
+
const myQueue = new Queue("my-queue", {
|
|
63
|
+
redis: { host: "localhost", port: 6379 },
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
const queueDash = new QueueDashClient({
|
|
67
|
+
apiKey: process.env.QUEUEDASH_API_KEY,
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
attachToBeeQueue(myQueue, queueDash);
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Configuration
|
|
74
|
+
|
|
75
|
+
### API Key
|
|
76
|
+
|
|
77
|
+
Get your API key from [QueueDash](https://queuedash.com):
|
|
78
|
+
|
|
79
|
+
1. Navigate to your environment settings
|
|
80
|
+
2. Click "API Keys"
|
|
81
|
+
3. Generate a new API key
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
# Set in your environment
|
|
85
|
+
QUEUEDASH_API_KEY=sk_live_...
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Advanced Options
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
interface QueueDashClientOptions {
|
|
92
|
+
// Required: Your API key from QueueDash
|
|
93
|
+
apiKey: string;
|
|
94
|
+
|
|
95
|
+
// Optional: Batch size for syncing jobs (defaults to 50)
|
|
96
|
+
batchSize?: number;
|
|
97
|
+
|
|
98
|
+
// Optional: Flush interval in milliseconds (defaults to 100)
|
|
99
|
+
flushInterval?: number;
|
|
100
|
+
|
|
101
|
+
// Optional: Max retry attempts with exponential backoff (defaults to 5)
|
|
102
|
+
maxRetries?: number;
|
|
103
|
+
|
|
104
|
+
// Optional: Request timeout in milliseconds (defaults to 30000)
|
|
105
|
+
requestTimeout?: number;
|
|
106
|
+
|
|
107
|
+
// Optional: Max jobs to queue in memory (defaults to 10000)
|
|
108
|
+
maxQueueSize?: number;
|
|
109
|
+
|
|
110
|
+
// Optional: Error handler called on critical failures
|
|
111
|
+
onError?: (error: Error) => void;
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Reliability & Robustness
|
|
116
|
+
|
|
117
|
+
The SDK is production-ready with multiple layers of protection:
|
|
118
|
+
|
|
119
|
+
**Retry Logic**
|
|
120
|
+
|
|
121
|
+
- Automatic retries up to 5 times (configurable)
|
|
122
|
+
- Exponential backoff: 1s → 2s → 4s → 8s → 16s → 30s (capped)
|
|
123
|
+
- Jobs preserved in local queue until successfully synced
|
|
124
|
+
|
|
125
|
+
**Circuit Breaker**
|
|
126
|
+
|
|
127
|
+
- Opens after 10 consecutive failures to prevent overwhelming the API
|
|
128
|
+
- Auto-resets after 60 seconds
|
|
129
|
+
- Prevents cascading failures
|
|
130
|
+
|
|
131
|
+
**Memory Protection**
|
|
132
|
+
|
|
133
|
+
- Queue size limit (10,000 jobs default) prevents memory leaks
|
|
134
|
+
- Oldest jobs dropped first if limit reached
|
|
135
|
+
- Warning logged when queue limit hit
|
|
136
|
+
|
|
137
|
+
**Graceful Shutdown**
|
|
138
|
+
|
|
139
|
+
- SIGTERM/SIGINT handlers flush pending jobs before exit
|
|
140
|
+
- Warns if jobs remain unsynced on crash
|
|
141
|
+
- No jobs lost during normal shutdown
|
|
142
|
+
|
|
143
|
+
**Request Safety**
|
|
144
|
+
|
|
145
|
+
- 30-second timeout on all HTTP requests
|
|
146
|
+
- Duplicate detection prevents same job syncing twice
|
|
147
|
+
- Network errors handled gracefully
|
|
148
|
+
|
|
149
|
+
## Features
|
|
150
|
+
|
|
151
|
+
- **Real-time sync**: Jobs are synced as events happen
|
|
152
|
+
- **Smart batching**: Events are automatically batched for performance
|
|
153
|
+
- **Auto-retry**: Failed syncs are automatically retried
|
|
154
|
+
- **Zero config**: Works out of the box with sensible defaults
|
|
155
|
+
- **TypeScript**: Full TypeScript support
|
|
156
|
+
|
|
157
|
+
## How It Works
|
|
158
|
+
|
|
159
|
+
The SDK automatically syncs your queue jobs to QueueDash's SaaS platform at `api.queuedash.com`. Just provide your API key and you're done - no additional configuration needed!
|
|
160
|
+
|
|
161
|
+
## License
|
|
162
|
+
|
|
163
|
+
MIT
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { JobData, QueueDashClientOptions } from "./types";
|
|
2
|
+
export declare class QueueDashClient {
|
|
3
|
+
private apiKey;
|
|
4
|
+
private apiUrl;
|
|
5
|
+
private batchSize;
|
|
6
|
+
private flushInterval;
|
|
7
|
+
private maxRetries;
|
|
8
|
+
private requestTimeout;
|
|
9
|
+
private maxQueueSize;
|
|
10
|
+
private onError?;
|
|
11
|
+
private jobQueue;
|
|
12
|
+
private flushTimer?;
|
|
13
|
+
private isFlushing;
|
|
14
|
+
private retryCount;
|
|
15
|
+
private circuitBreakerFailures;
|
|
16
|
+
private circuitBreakerOpen;
|
|
17
|
+
private circuitBreakerResetTimer?;
|
|
18
|
+
private syncingJobIds;
|
|
19
|
+
constructor(options: QueueDashClientOptions);
|
|
20
|
+
/**
|
|
21
|
+
* Queue a job for syncing
|
|
22
|
+
*/
|
|
23
|
+
syncJob(job: JobData): void;
|
|
24
|
+
/**
|
|
25
|
+
* Manually flush all pending jobs
|
|
26
|
+
*/
|
|
27
|
+
flush(): Promise<void>;
|
|
28
|
+
private openCircuitBreaker;
|
|
29
|
+
private logger;
|
|
30
|
+
/**
|
|
31
|
+
* Stop the client and flush remaining jobs
|
|
32
|
+
*/
|
|
33
|
+
stop(): Promise<void>;
|
|
34
|
+
private startFlushTimer;
|
|
35
|
+
private setupShutdownHandlers;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,sBAAsB,EAAgB,MAAM,SAAS,CAAC;AAExE,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,OAAO,CAAC,CAAyB;IAEzC,OAAO,CAAC,QAAQ,CAAiB;IACjC,OAAO,CAAC,UAAU,CAAC,CAAiB;IACpC,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,sBAAsB,CAAK;IACnC,OAAO,CAAC,kBAAkB,CAAS;IACnC,OAAO,CAAC,wBAAwB,CAAC,CAAiB;IAClD,OAAO,CAAC,aAAa,CAAqB;gBAE9B,OAAO,EAAE,sBAAsB;IA0B3C;;OAEG;IACI,OAAO,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI;IA8BlC;;OAEG;IACU,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAyGnC,OAAO,CAAC,kBAAkB;IAoB1B,OAAO,CAAC,MAAM;IASd;;OAEG;IACU,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAUlC,OAAO,CAAC,eAAe;IAavB,OAAO,CAAC,qBAAqB;CAkB9B"}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.QueueDashClient = void 0;
|
|
4
|
+
class QueueDashClient {
|
|
5
|
+
constructor(options) {
|
|
6
|
+
this.jobQueue = [];
|
|
7
|
+
this.isFlushing = false;
|
|
8
|
+
this.retryCount = 0;
|
|
9
|
+
this.circuitBreakerFailures = 0;
|
|
10
|
+
this.circuitBreakerOpen = false;
|
|
11
|
+
this.syncingJobIds = new Set();
|
|
12
|
+
if (!options.apiKey) {
|
|
13
|
+
throw new Error("QueueDash: apiKey is required");
|
|
14
|
+
}
|
|
15
|
+
this.apiKey = options.apiKey;
|
|
16
|
+
// Hardcoded SaaS API URL - can be overridden for staging only
|
|
17
|
+
this.apiUrl =
|
|
18
|
+
options.__dangerouslyOverrideApiUrl ||
|
|
19
|
+
(process.env.NODE_ENV === "production"
|
|
20
|
+
? "https://api.queuedash.com"
|
|
21
|
+
: "http://localhost:4001");
|
|
22
|
+
this.batchSize = options.batchSize || 50;
|
|
23
|
+
this.flushInterval = options.flushInterval || 100; // ms
|
|
24
|
+
this.maxRetries = options.maxRetries || 5;
|
|
25
|
+
this.requestTimeout = options.requestTimeout || 30000; // 30s default
|
|
26
|
+
this.maxQueueSize = options.maxQueueSize || 10000; // Prevent memory issues
|
|
27
|
+
this.onError = options.onError;
|
|
28
|
+
// Start auto-flush timer
|
|
29
|
+
this.startFlushTimer();
|
|
30
|
+
// Graceful shutdown handlers
|
|
31
|
+
this.setupShutdownHandlers();
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Queue a job for syncing
|
|
35
|
+
*/
|
|
36
|
+
syncJob(job) {
|
|
37
|
+
// Check circuit breaker
|
|
38
|
+
if (this.circuitBreakerOpen) {
|
|
39
|
+
this.logger("Circuit breaker open, dropping job");
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
// Prevent duplicate syncs of same job
|
|
43
|
+
const jobKey = `${job.queueName}:${job.jobId}`;
|
|
44
|
+
if (this.syncingJobIds.has(jobKey)) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
this.syncingJobIds.add(jobKey);
|
|
48
|
+
// Prevent memory leak - drop oldest jobs if queue too large
|
|
49
|
+
if (this.jobQueue.length >= this.maxQueueSize) {
|
|
50
|
+
const dropped = this.jobQueue.shift();
|
|
51
|
+
this.logger(`Queue size limit reached (${this.maxQueueSize}), dropping oldest job: ${dropped?.jobId}`);
|
|
52
|
+
}
|
|
53
|
+
this.jobQueue.push(job);
|
|
54
|
+
// Flush if batch size reached
|
|
55
|
+
if (this.jobQueue.length >= this.batchSize) {
|
|
56
|
+
this.flush();
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Manually flush all pending jobs
|
|
61
|
+
*/
|
|
62
|
+
async flush() {
|
|
63
|
+
if (this.isFlushing ||
|
|
64
|
+
this.jobQueue.length === 0 ||
|
|
65
|
+
this.circuitBreakerOpen) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
this.isFlushing = true;
|
|
69
|
+
const jobsToSync = [...this.jobQueue];
|
|
70
|
+
this.jobQueue = [];
|
|
71
|
+
try {
|
|
72
|
+
// Add timeout to fetch
|
|
73
|
+
const controller = new AbortController();
|
|
74
|
+
const timeoutId = setTimeout(() => controller.abort(), this.requestTimeout);
|
|
75
|
+
const response = await fetch(`${this.apiUrl}/api/v1/jobs/sync`, {
|
|
76
|
+
method: "POST",
|
|
77
|
+
headers: {
|
|
78
|
+
"Content-Type": "application/json",
|
|
79
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
80
|
+
},
|
|
81
|
+
body: JSON.stringify({
|
|
82
|
+
jobs: jobsToSync,
|
|
83
|
+
}),
|
|
84
|
+
signal: controller.signal,
|
|
85
|
+
});
|
|
86
|
+
clearTimeout(timeoutId);
|
|
87
|
+
if (!response.ok) {
|
|
88
|
+
const errorText = await response.text();
|
|
89
|
+
throw new Error(`HTTP ${response.status}: ${errorText}`);
|
|
90
|
+
}
|
|
91
|
+
const result = (await response.json());
|
|
92
|
+
if (!result.success && result.errors) {
|
|
93
|
+
console.warn("QueueDash: Some jobs failed to sync:", result.errors);
|
|
94
|
+
}
|
|
95
|
+
// Success - reset counters and clear syncing jobs
|
|
96
|
+
this.retryCount = 0;
|
|
97
|
+
this.circuitBreakerFailures = 0;
|
|
98
|
+
jobsToSync.forEach((job) => {
|
|
99
|
+
this.syncingJobIds.delete(`${job.queueName}:${job.jobId}`);
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
this.retryCount++;
|
|
104
|
+
this.circuitBreakerFailures++;
|
|
105
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
106
|
+
// Circuit breaker - open after 10 consecutive failures
|
|
107
|
+
if (this.circuitBreakerFailures >= 10) {
|
|
108
|
+
this.openCircuitBreaker();
|
|
109
|
+
}
|
|
110
|
+
// Check if we should retry
|
|
111
|
+
if (this.retryCount <= this.maxRetries) {
|
|
112
|
+
// Put jobs back in queue for retry with exponential backoff
|
|
113
|
+
this.jobQueue.unshift(...jobsToSync);
|
|
114
|
+
const backoffMs = Math.min(1000 * Math.pow(2, this.retryCount - 1), 30000); // Max 30s
|
|
115
|
+
this.logger(`Retry ${this.retryCount}/${this.maxRetries} after ${backoffMs}ms`, err);
|
|
116
|
+
// Schedule retry
|
|
117
|
+
setTimeout(() => {
|
|
118
|
+
if (this.jobQueue.length > 0) {
|
|
119
|
+
this.flush();
|
|
120
|
+
}
|
|
121
|
+
}, backoffMs);
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
// Max retries reached - clear syncing jobs and alert
|
|
125
|
+
this.retryCount = 0;
|
|
126
|
+
jobsToSync.forEach((job) => {
|
|
127
|
+
this.syncingJobIds.delete(`${job.queueName}:${job.jobId}`);
|
|
128
|
+
});
|
|
129
|
+
const errorMsg = `Failed to sync ${jobsToSync.length} jobs after ${this.maxRetries} retries`;
|
|
130
|
+
if (this.onError) {
|
|
131
|
+
this.onError(new Error(`${errorMsg}: ${err.message}`));
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
console.error(`QueueDash: ${errorMsg}`, err);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
finally {
|
|
139
|
+
this.isFlushing = false;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
openCircuitBreaker() {
|
|
143
|
+
if (this.circuitBreakerOpen)
|
|
144
|
+
return;
|
|
145
|
+
this.circuitBreakerOpen = true;
|
|
146
|
+
console.error("QueueDash: Circuit breaker opened after 10 consecutive failures. Will retry in 60s.");
|
|
147
|
+
// Auto-reset after 60 seconds
|
|
148
|
+
this.circuitBreakerResetTimer = setTimeout(() => {
|
|
149
|
+
this.circuitBreakerOpen = false;
|
|
150
|
+
this.circuitBreakerFailures = 0;
|
|
151
|
+
console.log("QueueDash: Circuit breaker reset, resuming sync attempts");
|
|
152
|
+
}, 60000);
|
|
153
|
+
if (this.circuitBreakerResetTimer.unref) {
|
|
154
|
+
this.circuitBreakerResetTimer.unref();
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
logger(message, error) {
|
|
158
|
+
if (this.onError && error) {
|
|
159
|
+
// If onError is provided, use it for warnings too
|
|
160
|
+
console.warn(`QueueDash: ${message}`, error);
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
console.warn(`QueueDash: ${message}`);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Stop the client and flush remaining jobs
|
|
168
|
+
*/
|
|
169
|
+
async stop() {
|
|
170
|
+
if (this.flushTimer) {
|
|
171
|
+
clearInterval(this.flushTimer);
|
|
172
|
+
}
|
|
173
|
+
if (this.circuitBreakerResetTimer) {
|
|
174
|
+
clearTimeout(this.circuitBreakerResetTimer);
|
|
175
|
+
}
|
|
176
|
+
await this.flush();
|
|
177
|
+
}
|
|
178
|
+
startFlushTimer() {
|
|
179
|
+
this.flushTimer = setInterval(() => {
|
|
180
|
+
if (this.jobQueue.length > 0) {
|
|
181
|
+
this.flush();
|
|
182
|
+
}
|
|
183
|
+
}, this.flushInterval);
|
|
184
|
+
// Don't keep process alive
|
|
185
|
+
if (this.flushTimer.unref) {
|
|
186
|
+
this.flushTimer.unref();
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
setupShutdownHandlers() {
|
|
190
|
+
const shutdown = async () => {
|
|
191
|
+
console.log("QueueDash: Graceful shutdown - flushing remaining jobs...");
|
|
192
|
+
await this.stop();
|
|
193
|
+
process.exit(0);
|
|
194
|
+
};
|
|
195
|
+
// Handle graceful shutdown
|
|
196
|
+
process.once("SIGTERM", shutdown);
|
|
197
|
+
process.once("SIGINT", shutdown);
|
|
198
|
+
process.once("beforeExit", () => {
|
|
199
|
+
if (this.jobQueue.length > 0) {
|
|
200
|
+
console.warn(`QueueDash: Process exiting with ${this.jobQueue.length} unsync'd jobs`);
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
exports.QueueDashClient = QueueDashClient;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { QueueDashClient } from "./client";
|
|
2
|
+
export { attachToBullMQ } from "./integrations/bullmq";
|
|
3
|
+
export { attachToBull } from "./integrations/bull";
|
|
4
|
+
export { attachToBeeQueue } from "./integrations/bee";
|
|
5
|
+
export type { QueueDashClientOptions, JobData, SyncResponse } from "./types";
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,YAAY,EAAE,sBAAsB,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.attachToBeeQueue = exports.attachToBull = exports.attachToBullMQ = exports.QueueDashClient = void 0;
|
|
4
|
+
var client_1 = require("./client");
|
|
5
|
+
Object.defineProperty(exports, "QueueDashClient", { enumerable: true, get: function () { return client_1.QueueDashClient; } });
|
|
6
|
+
var bullmq_1 = require("./integrations/bullmq");
|
|
7
|
+
Object.defineProperty(exports, "attachToBullMQ", { enumerable: true, get: function () { return bullmq_1.attachToBullMQ; } });
|
|
8
|
+
var bull_1 = require("./integrations/bull");
|
|
9
|
+
Object.defineProperty(exports, "attachToBull", { enumerable: true, get: function () { return bull_1.attachToBull; } });
|
|
10
|
+
var bee_1 = require("./integrations/bee");
|
|
11
|
+
Object.defineProperty(exports, "attachToBeeQueue", { enumerable: true, get: function () { return bee_1.attachToBeeQueue; } });
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { QueueDashClient } from "../client";
|
|
2
|
+
type BeeQueue = any;
|
|
3
|
+
/**
|
|
4
|
+
* Attach QueueDash monitoring to a Bee-Queue
|
|
5
|
+
*/
|
|
6
|
+
export declare function attachToBeeQueue(queue: BeeQueue, client: QueueDashClient): void;
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=bee.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bee.d.ts","sourceRoot":"","sources":["../../src/integrations/bee.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAG5C,KAAK,QAAQ,GAAG,GAAG,CAAC;AAGpB;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,QAAQ,EACf,MAAM,EAAE,eAAe,GACtB,IAAI,CAwCN"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.attachToBeeQueue = attachToBeeQueue;
|
|
4
|
+
/**
|
|
5
|
+
* Attach QueueDash monitoring to a Bee-Queue
|
|
6
|
+
*/
|
|
7
|
+
function attachToBeeQueue(queue, client) {
|
|
8
|
+
const queueName = queue.name;
|
|
9
|
+
const extractJobData = (job) => {
|
|
10
|
+
return {
|
|
11
|
+
jobId: String(job.id),
|
|
12
|
+
name: "default", // Bee-Queue doesn't have job names
|
|
13
|
+
queueName,
|
|
14
|
+
data: job.data,
|
|
15
|
+
opts: job.options || {},
|
|
16
|
+
addedAt: job.options?.timestamp
|
|
17
|
+
? new Date(job.options.timestamp)
|
|
18
|
+
: new Date(),
|
|
19
|
+
processedAt: null,
|
|
20
|
+
finishedAt: null,
|
|
21
|
+
priority: null,
|
|
22
|
+
delay: job.options?.delay,
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
// Listen to queue events
|
|
26
|
+
queue.on("succeeded", (job) => {
|
|
27
|
+
const jobData = extractJobData(job);
|
|
28
|
+
jobData.finishedAt = new Date();
|
|
29
|
+
client.syncJob(jobData);
|
|
30
|
+
});
|
|
31
|
+
queue.on("failed", (job, err) => {
|
|
32
|
+
const jobData = extractJobData(job);
|
|
33
|
+
jobData.failedReason = err.message;
|
|
34
|
+
jobData.stacktrace = err.stack ? [err.stack] : undefined;
|
|
35
|
+
jobData.finishedAt = new Date();
|
|
36
|
+
client.syncJob(jobData);
|
|
37
|
+
});
|
|
38
|
+
queue.on("retrying", (job) => {
|
|
39
|
+
const jobData = extractJobData(job);
|
|
40
|
+
jobData.retriedAt = new Date();
|
|
41
|
+
client.syncJob(jobData);
|
|
42
|
+
});
|
|
43
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { QueueDashClient } from "../client";
|
|
2
|
+
type BullQueue = any;
|
|
3
|
+
/**
|
|
4
|
+
* Attach QueueDash monitoring to a Bull queue
|
|
5
|
+
*/
|
|
6
|
+
export declare function attachToBull(queue: BullQueue, client: QueueDashClient): void;
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=bull.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bull.d.ts","sourceRoot":"","sources":["../../src/integrations/bull.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAG5C,KAAK,SAAS,GAAG,GAAG,CAAC;AAGrB;;GAEG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CA4C5E"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.attachToBull = attachToBull;
|
|
4
|
+
/**
|
|
5
|
+
* Attach QueueDash monitoring to a Bull queue
|
|
6
|
+
*/
|
|
7
|
+
function attachToBull(queue, client) {
|
|
8
|
+
const queueName = queue.name;
|
|
9
|
+
const extractJobData = (job) => {
|
|
10
|
+
return {
|
|
11
|
+
jobId: job.id,
|
|
12
|
+
name: job.name || "default",
|
|
13
|
+
queueName,
|
|
14
|
+
data: job.data,
|
|
15
|
+
opts: job.opts,
|
|
16
|
+
addedAt: new Date(job.timestamp),
|
|
17
|
+
processedAt: job.processedOn ? new Date(job.processedOn) : null,
|
|
18
|
+
finishedAt: job.finishedOn ? new Date(job.finishedOn) : null,
|
|
19
|
+
failedReason: job.failedReason,
|
|
20
|
+
stacktrace: job.stacktrace,
|
|
21
|
+
priority: job.opts?.priority,
|
|
22
|
+
delay: job.opts?.delay,
|
|
23
|
+
timestamp: job.timestamp,
|
|
24
|
+
progress: job._progress || null,
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
// Listen to queue events
|
|
28
|
+
queue.on("completed", (job) => {
|
|
29
|
+
client.syncJob(extractJobData(job));
|
|
30
|
+
});
|
|
31
|
+
queue.on("failed", (job) => {
|
|
32
|
+
if (job) {
|
|
33
|
+
client.syncJob(extractJobData(job));
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
queue.on("active", (job) => {
|
|
37
|
+
client.syncJob(extractJobData(job));
|
|
38
|
+
});
|
|
39
|
+
queue.on("progress", (job) => {
|
|
40
|
+
client.syncJob(extractJobData(job));
|
|
41
|
+
});
|
|
42
|
+
queue.on("removed", (job) => {
|
|
43
|
+
client.syncJob(extractJobData(job));
|
|
44
|
+
});
|
|
45
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { QueueDashClient } from "../client";
|
|
2
|
+
type BullMQQueue = any;
|
|
3
|
+
/**
|
|
4
|
+
* Attach QueueDash monitoring to a BullMQ queue
|
|
5
|
+
*/
|
|
6
|
+
export declare function attachToBullMQ(queue: BullMQQueue, client: QueueDashClient): void;
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=bullmq.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bullmq.d.ts","sourceRoot":"","sources":["../../src/integrations/bullmq.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAG5C,KAAK,WAAW,GAAG,GAAG,CAAC;AAGvB;;GAEG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,WAAW,EAClB,MAAM,EAAE,eAAe,GACtB,IAAI,CA6CN"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.attachToBullMQ = attachToBullMQ;
|
|
4
|
+
/**
|
|
5
|
+
* Attach QueueDash monitoring to a BullMQ queue
|
|
6
|
+
*/
|
|
7
|
+
function attachToBullMQ(queue, client) {
|
|
8
|
+
const queueName = queue.name;
|
|
9
|
+
const extractJobData = (job) => {
|
|
10
|
+
return {
|
|
11
|
+
jobId: job.id,
|
|
12
|
+
name: job.name,
|
|
13
|
+
queueName,
|
|
14
|
+
data: job.data,
|
|
15
|
+
opts: job.opts,
|
|
16
|
+
addedAt: new Date(job.timestamp),
|
|
17
|
+
processedAt: job.processedOn ? new Date(job.processedOn) : null,
|
|
18
|
+
finishedAt: job.finishedOn ? new Date(job.finishedOn) : null,
|
|
19
|
+
failedReason: job.failedReason,
|
|
20
|
+
stacktrace: job.stacktrace,
|
|
21
|
+
retriedAt: job.retriedAt ? new Date(job.retriedAt) : null,
|
|
22
|
+
priority: job.opts?.priority,
|
|
23
|
+
delay: job.opts?.delay,
|
|
24
|
+
timestamp: job.timestamp,
|
|
25
|
+
progress: job.progress || null,
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
// Listen to queue events
|
|
29
|
+
queue.on("completed", (job) => {
|
|
30
|
+
client.syncJob(extractJobData(job));
|
|
31
|
+
});
|
|
32
|
+
queue.on("failed", (job) => {
|
|
33
|
+
if (job) {
|
|
34
|
+
client.syncJob(extractJobData(job));
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
queue.on("active", (job) => {
|
|
38
|
+
client.syncJob(extractJobData(job));
|
|
39
|
+
});
|
|
40
|
+
queue.on("progress", (job) => {
|
|
41
|
+
client.syncJob(extractJobData(job));
|
|
42
|
+
});
|
|
43
|
+
queue.on("removed", (job) => {
|
|
44
|
+
client.syncJob(extractJobData(job));
|
|
45
|
+
});
|
|
46
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export interface QueueDashClientOptions {
|
|
2
|
+
apiKey: string;
|
|
3
|
+
batchSize?: number;
|
|
4
|
+
flushInterval?: number;
|
|
5
|
+
maxRetries?: number;
|
|
6
|
+
requestTimeout?: number;
|
|
7
|
+
maxQueueSize?: number;
|
|
8
|
+
onError?: (error: Error) => void;
|
|
9
|
+
/** @internal - Not for public use. Override API URL for staging environments only. */
|
|
10
|
+
__dangerouslyOverrideApiUrl?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface JobData {
|
|
13
|
+
jobId: string;
|
|
14
|
+
name: string;
|
|
15
|
+
queueName: string;
|
|
16
|
+
data?: Record<string, unknown>;
|
|
17
|
+
opts?: Record<string, unknown>;
|
|
18
|
+
addedAt: Date;
|
|
19
|
+
processedAt?: Date | null;
|
|
20
|
+
finishedAt?: Date | null;
|
|
21
|
+
failedReason?: string;
|
|
22
|
+
stacktrace?: string[];
|
|
23
|
+
logs?: string[];
|
|
24
|
+
retriedAt?: Date | null;
|
|
25
|
+
priority?: number | null;
|
|
26
|
+
delay?: number | null;
|
|
27
|
+
timestamp?: number | null;
|
|
28
|
+
progress?: number | null;
|
|
29
|
+
}
|
|
30
|
+
export interface SyncResponse {
|
|
31
|
+
success: boolean;
|
|
32
|
+
synced: number;
|
|
33
|
+
errors?: string[];
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,sFAAsF;IACtF,2BAA2B,CAAC,EAAE,MAAM,CAAC;CACtC;AAED,MAAM,WAAW,OAAO;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,OAAO,EAAE,IAAI,CAAC;IACd,WAAW,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IAC1B,UAAU,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,SAAS,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB"}
|
package/dist/types.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@queuedash/sdk",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "QueueDash SDK for real-time queue monitoring",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist",
|
|
9
|
+
"README.md"
|
|
10
|
+
],
|
|
11
|
+
"keywords": [
|
|
12
|
+
"queue",
|
|
13
|
+
"bullmq",
|
|
14
|
+
"bull",
|
|
15
|
+
"bee-queue",
|
|
16
|
+
"monitoring",
|
|
17
|
+
"dashboard"
|
|
18
|
+
],
|
|
19
|
+
"author": "QueueDash",
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"peerDependencies": {
|
|
22
|
+
"bullmq": ">=3.0.0",
|
|
23
|
+
"bull": ">=4.0.0",
|
|
24
|
+
"bee-queue": ">=1.0.0"
|
|
25
|
+
},
|
|
26
|
+
"peerDependenciesMeta": {
|
|
27
|
+
"bullmq": {
|
|
28
|
+
"optional": true
|
|
29
|
+
},
|
|
30
|
+
"bull": {
|
|
31
|
+
"optional": true
|
|
32
|
+
},
|
|
33
|
+
"bee-queue": {
|
|
34
|
+
"optional": true
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@types/node": "^20.0.0",
|
|
39
|
+
"typescript": "^5.9.3"
|
|
40
|
+
},
|
|
41
|
+
"scripts": {
|
|
42
|
+
"build": "tsc"
|
|
43
|
+
}
|
|
44
|
+
}
|