worker-que 1.0.0 → 1.0.1

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/DASHBOARD.md CHANGED
@@ -1,26 +1,22 @@
1
- # Dashboard Documentation
1
+ # Dashboard Guide
2
2
 
3
- A beautiful, real-time web dashboard for monitoring and managing your Que job queue.
3
+ Complete guide for the worker-que web dashboard - a real-time monitoring and management interface for your job queue.
4
4
 
5
- ## Features
5
+ ## Table of Contents
6
6
 
7
- - 📊 **Real-time Statistics** - Monitor total, ready, scheduled, and failed jobs
8
- - 📈 **Visual Analytics** - Charts showing job distribution by queue and class
9
- - 🔍 **Advanced Filtering** - Filter jobs by status, queue, and job class
10
- - 🔄 **Job Management** - Retry failed jobs or delete jobs directly from the UI
11
- - 🎨 **Modern UI** - Beautiful, responsive design that works on all devices
12
- - 🔐 **Authentication** - Built-in support for custom authentication
13
- - ⚡ **Auto-refresh** - Configurable real-time updates
7
+ - [Quick Start](#quick-start)
8
+ - [Configuration](#configuration)
9
+ - [Authentication](#authentication)
10
+ - [API Reference](#api-reference)
11
+ - [Troubleshooting](#troubleshooting)
12
+ - [Production Deployment](#production-deployment)
14
13
 
15
14
  ## Quick Start
16
15
 
17
16
  ### Installation
18
17
 
19
- The dashboard requires Express.js:
20
-
21
18
  ```bash
22
- npm install express
23
- npm install --save-dev @types/express # If using TypeScript
19
+ npm install worker-que express pg
24
20
  ```
25
21
 
26
22
  ### Basic Setup
@@ -28,7 +24,7 @@ npm install --save-dev @types/express # If using TypeScript
28
24
  ```typescript
29
25
  import express from 'express';
30
26
  import { Pool } from 'pg';
31
- import { createDashboard } from 'que-ts/dashboard';
27
+ import { createDashboard } from 'worker-que/dist/dashboard';
32
28
 
33
29
  const app = express();
34
30
  const pool = new Pool({
@@ -39,7 +35,7 @@ const pool = new Pool({
39
35
  password: 'password',
40
36
  });
41
37
 
42
- // Mount dashboard at /admin/queue
38
+ // Mount dashboard
43
39
  app.use('/admin/queue', createDashboard(pool));
44
40
 
45
41
  app.listen(3000, () => {
@@ -47,94 +43,122 @@ app.listen(3000, () => {
47
43
  });
48
44
  ```
49
45
 
50
- That's it! Visit http://localhost:3000/admin/queue to see your dashboard.
46
+ That's it! Visit `http://localhost:3000/admin/queue` to see your dashboard.
47
+
48
+ ## Features
49
+
50
+ ### Real-time Statistics
51
+
52
+ - **Total Jobs** - All jobs in the queue
53
+ - **Ready** - Jobs ready to process
54
+ - **Scheduled** - Jobs scheduled for future
55
+ - **Failed** - Jobs that have errored
56
+
57
+ ### Visual Analytics
58
+
59
+ - **Jobs by Queue** - Bar chart showing distribution across queues
60
+ - **Jobs by Class** - Bar chart showing distribution by job type
61
+
62
+ ### Job Management
63
+
64
+ - **Filter** - By status, queue, and job class
65
+ - **Search** - Find specific jobs
66
+ - **Pagination** - Browse through large job lists
67
+ - **Retry** - Restart failed jobs
68
+ - **Delete** - Remove jobs from queue
69
+
70
+ ### Recent Failures
71
+
72
+ View the most recent failed jobs with:
73
+ - Error messages
74
+ - Error counts
75
+ - Quick retry/delete actions
51
76
 
52
- ## Configuration Options
77
+ ## Configuration
53
78
 
54
- ### DashboardOptions
79
+ ### Dashboard Options
55
80
 
56
81
  ```typescript
57
82
  interface DashboardOptions {
58
- // Dashboard title (shown in header)
59
- title?: string; // Default: 'Que Dashboard'
60
-
61
- // Base path for API routes
62
- basePath?: string; // Default: '/que'
63
-
64
- // Auto-refresh interval in milliseconds
65
- refreshInterval?: number; // Default: 5000 (5 seconds)
66
-
67
- // Maximum number of recent failures to show
68
- maxRecentFailures?: number; // Default: 50
69
-
70
- // Authentication function
71
- auth?: (req, res, next) => boolean | Promise<boolean>;
83
+ title?: string; // Dashboard title (default: 'Que Dashboard')
84
+ basePath?: string; // Base path for API routes (default: '/que')
85
+ refreshInterval?: number; // Auto-refresh interval in ms (default: 5000)
86
+ maxRecentFailures?: number; // Max failures to show (default: 50)
87
+ auth?: (req, res, next) => boolean | Promise<boolean>; // Auth function
72
88
  }
73
89
  ```
74
90
 
75
91
  ### Examples
76
92
 
77
- #### Custom Title and Refresh Rate
93
+ #### Custom Title and Refresh
78
94
 
79
95
  ```typescript
80
96
  app.use('/queue', createDashboard(pool, {
81
97
  title: 'Production Job Queue',
98
+ basePath: '/queue',
82
99
  refreshInterval: 2000, // Refresh every 2 seconds
83
100
  }));
84
101
  ```
85
102
 
86
- #### With Different Base Path
103
+ #### Different Mount Path
87
104
 
88
105
  ```typescript
89
106
  app.use('/jobs', createDashboard(pool, {
90
- basePath: '/jobs', // Important: must match mount path
107
+ basePath: '/jobs', // Must match mount path
91
108
  }));
109
+ // Visit http://localhost:3000/jobs
92
110
  ```
93
111
 
94
112
  ## Authentication
95
113
 
96
- ### Basic Authentication
114
+ The dashboard supports flexible authentication through the `auth` function.
115
+
116
+ ### API Key Authentication
97
117
 
98
118
  ```typescript
99
119
  app.use('/admin/queue', createDashboard(pool, {
100
- auth: (req, res, next) => {
101
- const apiKey = req.headers['x-api-key'];
102
- return apiKey === 'your-secret-api-key';
120
+ auth: (req) => {
121
+ return req.headers['x-api-key'] === process.env.DASHBOARD_API_KEY;
103
122
  }
104
123
  }));
105
124
  ```
106
125
 
107
- ### Session-based Authentication
126
+ **Usage:**
127
+ ```bash
128
+ curl -H "X-API-Key: your-secret-key" http://localhost:3000/admin/queue/api/stats
129
+ ```
130
+
131
+ ### Session-Based Authentication
108
132
 
109
133
  ```typescript
110
134
  import session from 'express-session';
111
135
 
112
136
  app.use(session({
113
- secret: 'your-session-secret',
137
+ secret: process.env.SESSION_SECRET,
114
138
  resave: false,
115
139
  saveUninitialized: false,
116
140
  }));
117
141
 
118
142
  app.use('/admin/queue', createDashboard(pool, {
119
- auth: (req, res, next) => {
120
- // Only allow authenticated admins
121
- return req.session?.user?.role === 'admin';
143
+ auth: (req) => {
144
+ return req.session?.user?.isAdmin === true;
122
145
  }
123
146
  }));
124
147
  ```
125
148
 
126
- ### Async Authentication (Database Check)
149
+ ### JWT Authentication
127
150
 
128
151
  ```typescript
152
+ import jwt from 'jsonwebtoken';
153
+
129
154
  app.use('/admin/queue', createDashboard(pool, {
130
- auth: async (req, res, next) => {
131
- const token = req.headers['authorization']?.split(' ')[1];
132
-
133
- if (!token) return false;
134
-
155
+ auth: (req) => {
135
156
  try {
136
- const user = await verifyToken(token);
137
- return user.hasPermission('view-queue');
157
+ const token = req.headers.authorization?.split(' ')[1];
158
+ if (!token) return false;
159
+
160
+ const decoded = jwt.verify(token, process.env.JWT_SECRET);
161
+ return decoded.role === 'admin';
138
162
  } catch {
139
163
  return false;
140
164
  }
@@ -142,27 +166,21 @@ app.use('/admin/queue', createDashboard(pool, {
142
166
  }));
143
167
  ```
144
168
 
145
- ### JWT Authentication
169
+ ### Async Database Authentication
146
170
 
147
171
  ```typescript
148
- import jwt from 'jsonwebtoken';
149
-
150
172
  app.use('/admin/queue', createDashboard(pool, {
151
- auth: (req, res, next) => {
152
- try {
153
- const token = req.cookies.auth_token;
154
- const decoded = jwt.verify(token, process.env.JWT_SECRET);
155
- return decoded.role === 'admin';
156
- } catch {
157
- return false;
158
- }
173
+ auth: async (req) => {
174
+ const token = req.headers.authorization;
175
+ const user = await verifyUserToken(token);
176
+ return user?.hasPermission('view-queue');
159
177
  }
160
178
  }));
161
179
  ```
162
180
 
163
- ## API Routes
181
+ ## API Reference
164
182
 
165
- The dashboard exposes several API routes that you can use programmatically:
183
+ The dashboard exposes REST API endpoints for programmatic access.
166
184
 
167
185
  ### GET /api/stats
168
186
 
@@ -193,18 +211,18 @@ Get queue statistics.
193
211
 
194
212
  ### GET /api/jobs
195
213
 
196
- Get paginated list of jobs with optional filters.
214
+ Get paginated list of jobs with filters.
197
215
 
198
216
  **Query Parameters:**
199
- - `status`: Filter by status (`all`, `ready`, `scheduled`, `failed`)
200
- - `queue`: Filter by queue name
201
- - `jobClass`: Filter by job class
202
- - `limit`: Number of results per page (default: 50)
203
- - `offset`: Pagination offset (default: 0)
217
+ - `status` - Filter by status (`all`, `ready`, `scheduled`, `failed`)
218
+ - `queue` - Filter by queue name
219
+ - `jobClass` - Filter by job class
220
+ - `limit` - Results per page (default: 50)
221
+ - `offset` - Pagination offset (default: 0)
204
222
 
205
223
  **Example:**
206
224
  ```
207
- GET /api/jobs?status=failed&queue=critical&limit=20&offset=0
225
+ GET /api/jobs?status=failed&queue=critical&limit=20
208
226
  ```
209
227
 
210
228
  **Response:**
@@ -217,7 +235,7 @@ GET /api/jobs?status=failed&queue=critical&limit=20&offset=0
217
235
  "priority": 10,
218
236
  "runAt": "2024-01-15T14:30:00Z",
219
237
  "jobClass": "ProcessPayment",
220
- "args": [{ "amount": 100, "userId": 456 }],
238
+ "args": [{ "amount": 100 }],
221
239
  "errorCount": 3,
222
240
  "lastError": "Payment gateway timeout"
223
241
  }
@@ -282,16 +300,16 @@ Get list of all job class names.
282
300
 
283
301
  **Response:**
284
302
  ```json
285
- ["SendEmail", "ProcessPayment", "GenerateReport", "SendReminder"]
303
+ ["SendEmail", "ProcessPayment", "GenerateReport"]
286
304
  ```
287
305
 
288
306
  ## Programmatic Usage
289
307
 
290
- You can also use the dashboard service directly in your code:
308
+ You can use the dashboard service directly in your code:
291
309
 
292
310
  ```typescript
293
311
  import { Pool } from 'pg';
294
- import { DashboardService } from 'que-ts/dashboard';
312
+ import { DashboardService } from 'worker-que/dist/dashboard';
295
313
 
296
314
  const pool = new Pool({ /* config */ });
297
315
  const dashboard = new DashboardService(pool);
@@ -299,7 +317,6 @@ const dashboard = new DashboardService(pool);
299
317
  // Get statistics
300
318
  const stats = await dashboard.getStats();
301
319
  console.log(`Total jobs: ${stats.total}`);
302
- console.log(`Failed jobs: ${stats.failed}`);
303
320
 
304
321
  // Get jobs with filters
305
322
  const { jobs, total } = await dashboard.getJobs({
@@ -321,236 +338,221 @@ const queues = await dashboard.getQueues();
321
338
  const jobClasses = await dashboard.getJobClasses();
322
339
  ```
323
340
 
324
- ## Integration Examples
341
+ ## Troubleshooting
325
342
 
326
- ### With Existing Express App
343
+ ### Error: "Cannot GET /que/api/jobs"
327
344
 
328
- ```typescript
329
- import express from 'express';
330
- import { Pool } from 'pg';
331
- import { createDashboard } from 'que-ts/dashboard';
345
+ **Problem:** Dashboard routes not mounted.
332
346
 
333
- const app = express();
334
- const pool = new Pool({ /* config */ });
335
-
336
- // Your existing routes
337
- app.get('/', (req, res) => {
338
- res.send('Home page');
339
- });
347
+ **Solution:** Make sure you mount the dashboard with `app.use()`:
340
348
 
341
- app.get('/api/users', (req, res) => {
342
- // Your API
343
- });
349
+ ```typescript
350
+ import { createDashboard } from 'worker-que/dist/dashboard';
344
351
 
345
- // Add dashboard
346
- app.use('/admin/queue', createDashboard(pool, {
347
- title: 'My App Queue',
348
- auth: (req) => req.session?.isAdmin,
352
+ app.use('/que', createDashboard(pool, {
353
+ basePath: '/que', // Must match mount path
349
354
  }));
350
-
351
- app.listen(3000);
352
355
  ```
353
356
 
354
- ### With Multiple Workers
357
+ ### Dashboard Shows No Data
355
358
 
356
- ```typescript
357
- import express from 'express';
358
- import { Pool } from 'pg';
359
- import { createDashboard } from 'que-ts/dashboard';
360
- import { Worker } from 'que-ts';
359
+ **Problem:** Database table doesn't exist or is empty.
361
360
 
362
- const app = express();
363
- const pool = new Pool({ /* config */ });
361
+ **Solution:**
362
+ 1. Create the `que_jobs` table using the schema
363
+ 2. Check database connection
364
+ 3. Verify table has jobs: `SELECT COUNT(*) FROM que_jobs;`
364
365
 
365
- // Create dashboard
366
- app.use('/queue', createDashboard(pool));
366
+ ### Authentication Not Working
367
367
 
368
- // Start multiple workers
369
- const criticalWorker = new Worker(
370
- { /* db config */ },
371
- { queue: 'critical', interval: 100 }
372
- );
368
+ **Problem:** Auth function not returning correct value.
373
369
 
374
- const backgroundWorker = new Worker(
375
- { /* db config */ },
376
- { queue: 'background', interval: 5000 }
377
- );
370
+ **Solution:**
371
+ - Make sure auth function returns `true` or `false`
372
+ - For async auth, declare function as `async`
373
+ - Check browser console for 403 errors
378
374
 
379
- // Register handlers and start workers
380
- criticalWorker.register('ProcessPayment', handlePayment);
381
- backgroundWorker.register('GenerateReport', handleReport);
375
+ ### Slow Dashboard Performance
382
376
 
383
- criticalWorker.work();
384
- backgroundWorker.work();
377
+ **Solutions:**
385
378
 
386
- app.listen(3000);
379
+ 1. Add database indexes:
380
+ ```sql
381
+ CREATE INDEX idx_que_jobs_run_at ON que_jobs(run_at);
382
+ CREATE INDEX idx_que_jobs_error_count ON que_jobs(error_count);
383
+ CREATE INDEX idx_que_jobs_queue ON que_jobs(queue);
384
+ CREATE INDEX idx_que_jobs_job_class ON que_jobs(job_class);
387
385
  ```
388
386
 
389
- ### Behind a Proxy (nginx, etc.)
390
-
391
- If running behind a proxy, make sure to set the correct `basePath`:
392
-
387
+ 2. Increase refresh interval:
393
388
  ```typescript
394
- // nginx config:
395
- // location /app/queue {
396
- // proxy_pass http://localhost:3000/queue;
397
- // }
389
+ createDashboard(pool, { refreshInterval: 10000 })
390
+ ```
398
391
 
399
- app.use('/queue', createDashboard(pool, {
400
- basePath: '/queue', // Not /app/queue - that's handled by nginx
401
- }));
392
+ 3. Reduce max failures shown:
393
+ ```typescript
394
+ createDashboard(pool, { maxRecentFailures: 25 })
402
395
  ```
403
396
 
404
- ## Deployment Considerations
397
+ ## Production Deployment
405
398
 
406
- ### Production Checklist
399
+ ### Environment Variables
407
400
 
408
- - [ ] **Enable Authentication** - Never deploy without auth in production
409
- - [ ] **Use HTTPS** - Protect sensitive job data
410
- - [ ] **Restrict Access** - Use firewall rules or network policies
411
- - [ ] **Monitor Performance** - Dashboard queries can impact database
412
- - [ ] **Set Reasonable Refresh Interval** - Don't overwhelm your database
413
- - [ ] **Use Connection Pooling** - Reuse database connections
414
- - [ ] **Enable Logging** - Track dashboard access and actions
401
+ ```bash
402
+ # Dashboard
403
+ DASHBOARD_PATH=/admin/queue
404
+ DASHBOARD_TITLE=Production Queue
405
+ DASHBOARD_REFRESH_MS=5000
406
+ DASHBOARD_API_KEY=your-secret-key
407
+
408
+ # Database
409
+ DB_HOST=postgres
410
+ DB_PORT=5432
411
+ DB_NAME=myapp
412
+ DB_USER=postgres
413
+ DB_PASSWORD=secret
414
+ ```
415
415
 
416
- ### Environment Variables
416
+ ### Secure Configuration
417
417
 
418
418
  ```typescript
419
- import { createDashboard } from 'que-ts/dashboard';
419
+ require('dotenv').config();
420
420
 
421
421
  const pool = new Pool({
422
- connectionString: process.env.DATABASE_URL,
422
+ host: process.env.DB_HOST,
423
+ port: parseInt(process.env.DB_PORT),
424
+ database: process.env.DB_NAME,
425
+ user: process.env.DB_USER,
426
+ password: process.env.DB_PASSWORD,
423
427
  ssl: process.env.NODE_ENV === 'production',
424
428
  });
425
429
 
426
- app.use(process.env.DASHBOARD_PATH || '/admin/queue',
427
- createDashboard(pool, {
428
- title: process.env.APP_NAME || 'Queue Dashboard',
429
- refreshInterval: parseInt(process.env.DASHBOARD_REFRESH_MS || '5000'),
430
- auth: (req) => {
431
- const apiKey = req.headers['x-api-key'];
432
- return apiKey === process.env.DASHBOARD_API_KEY;
433
- },
434
- })
435
- );
430
+ app.use(process.env.DASHBOARD_PATH, createDashboard(pool, {
431
+ title: process.env.DASHBOARD_TITLE,
432
+ basePath: process.env.DASHBOARD_PATH,
433
+ refreshInterval: parseInt(process.env.DASHBOARD_REFRESH_MS),
434
+ auth: (req) => {
435
+ return req.headers['x-api-key'] === process.env.DASHBOARD_API_KEY;
436
+ },
437
+ }));
438
+ ```
439
+
440
+ ### Behind a Reverse Proxy
441
+
442
+ If running behind nginx or similar:
443
+
444
+ ```nginx
445
+ # nginx.conf
446
+ location /admin/queue {
447
+ proxy_pass http://localhost:3000/admin/queue;
448
+ proxy_http_version 1.1;
449
+ proxy_set_header Upgrade $http_upgrade;
450
+ proxy_set_header Connection 'upgrade';
451
+ proxy_set_header Host $host;
452
+ proxy_cache_bypass $http_upgrade;
453
+ }
436
454
  ```
437
455
 
438
- ### Docker Example
456
+ ### Docker Deployment
439
457
 
440
458
  ```dockerfile
441
459
  FROM node:18-alpine
442
-
443
460
  WORKDIR /app
444
461
  COPY package*.json ./
445
462
  RUN npm ci --only=production
446
-
447
463
  COPY . .
448
-
449
464
  ENV NODE_ENV=production
450
- ENV DASHBOARD_PATH=/queue
451
- ENV DASHBOARD_REFRESH_MS=5000
452
-
465
+ ENV PORT=3000
453
466
  EXPOSE 3000
454
-
455
467
  CMD ["node", "dist/server.js"]
456
468
  ```
457
469
 
458
- ## Troubleshooting
470
+ ```bash
471
+ docker build -t queue-dashboard .
472
+ docker run -p 3000:3000 \
473
+ -e DB_HOST=postgres \
474
+ -e DB_NAME=myapp \
475
+ -e DASHBOARD_API_KEY=secret \
476
+ queue-dashboard
477
+ ```
459
478
 
460
- ### Dashboard shows "Failed to load jobs"
479
+ ### Security Checklist
461
480
 
462
- **Check:**
463
- 1. Database connection is working
464
- 2. `que_jobs` table exists
465
- 3. User has SELECT permissions on `que_jobs`
481
+ - [ ] Enable authentication
482
+ - [ ] Use HTTPS in production
483
+ - [ ] Restrict network access
484
+ - [ ] Use environment variables for secrets
485
+ - [ ] Enable rate limiting
486
+ - [ ] Use read-only database user for dashboard
487
+ - [ ] Regular security audits
488
+ - [ ] Keep dependencies updated
466
489
 
467
- ### Authentication not working
490
+ ## Complete Example
468
491
 
469
- **Check:**
470
- 1. Auth function returns `true` or `false` (not undefined)
471
- 2. For async auth, ensure function is declared `async`
472
- 3. Check browser console for 403 errors
492
+ ```typescript
493
+ import express from 'express';
494
+ import session from 'express-session';
495
+ import { Pool } from 'pg';
496
+ import { createDashboard } from 'worker-que/dist/dashboard';
497
+ import { Client, Worker } from 'worker-que';
473
498
 
474
- ### Slow dashboard performance
499
+ const app = express();
500
+ const dbConfig = {
501
+ host: process.env.DB_HOST,
502
+ port: parseInt(process.env.DB_PORT),
503
+ database: process.env.DB_NAME,
504
+ user: process.env.DB_USER,
505
+ password: process.env.DB_PASSWORD,
506
+ };
507
+
508
+ const pool = new Pool(dbConfig);
509
+ const client = new Client(dbConfig);
510
+ const worker = new Worker(dbConfig);
511
+
512
+ // Setup session
513
+ app.use(session({
514
+ secret: process.env.SESSION_SECRET,
515
+ resave: false,
516
+ saveUninitialized: false,
517
+ }));
475
518
 
476
- **Solutions:**
477
- 1. Increase `refreshInterval` to reduce polling frequency
478
- 2. Add database indexes:
479
- ```sql
480
- CREATE INDEX idx_que_jobs_run_at ON que_jobs(run_at);
481
- CREATE INDEX idx_que_jobs_error_count ON que_jobs(error_count);
482
- CREATE INDEX idx_que_jobs_queue ON que_jobs(queue);
483
- CREATE INDEX idx_que_jobs_job_class ON que_jobs(job_class);
484
- ```
485
- 3. Reduce `maxRecentFailures` option
486
- 4. Use database connection pooling
487
-
488
- ### Dashboard not refreshing
489
-
490
- **Check:**
491
- 1. JavaScript is enabled in browser
492
- 2. No console errors in browser dev tools
493
- 3. API endpoints are accessible (check network tab)
494
- 4. CORS is configured if dashboard is on different domain
495
-
496
- ## Screenshots
497
-
498
- ### Main Dashboard
499
- ![Dashboard Overview](docs/images/dashboard-overview.png)
500
-
501
- Shows:
502
- - Real-time job statistics
503
- - Ready, scheduled, and failed job counts
504
- - Visual charts for queue and class distribution
505
-
506
- ### Jobs List
507
- ![Jobs List](docs/images/jobs-list.png)
508
-
509
- Features:
510
- - Filter by status, queue, and job class
511
- - Pagination for large job lists
512
- - Quick actions to retry or delete jobs
519
+ // Register job handlers
520
+ worker.register('SendEmail', async (job) => {
521
+ // Email logic
522
+ });
513
523
 
514
- ### Recent Failures
515
- ![Recent Failures](docs/images/failures.png)
524
+ // Mount dashboard with auth
525
+ app.use('/admin/queue', createDashboard(pool, {
526
+ title: 'Production Queue',
527
+ basePath: '/admin/queue',
528
+ refreshInterval: 3000,
529
+ auth: (req) => req.session?.user?.isAdmin === true,
530
+ }));
516
531
 
517
- Displays:
518
- - Jobs that have failed
519
- - Error messages
520
- - Retry and delete actions
521
-
522
- ## Customization
523
-
524
- ### Custom Styles
525
-
526
- The dashboard uses inline styles for portability. To customize:
527
-
528
- 1. Create your own view template:
529
- ```typescript
530
- import { getDashboardHTML } from 'que-ts/dashboard/views';
531
-
532
- // Extend or modify the HTML
533
- const customHTML = getDashboardHTML(options)
534
- .replace('background: #667eea', 'background: #your-color');
535
- ```
536
-
537
- 2. Or mount your own routes:
538
- ```typescript
539
- import { DashboardService } from 'que-ts/dashboard';
540
-
541
- const service = new DashboardService(pool);
542
-
543
- app.get('/custom-dashboard', (req, res) => {
544
- // Your custom HTML using service.getStats()
545
- });
546
- ```
532
+ // Start worker
533
+ worker.work();
534
+
535
+ // Start server
536
+ const PORT = process.env.PORT || 3000;
537
+ app.listen(PORT, () => {
538
+ console.log(`Dashboard: http://localhost:${PORT}/admin/queue`);
539
+ });
540
+
541
+ // Graceful shutdown
542
+ process.on('SIGTERM', async () => {
543
+ await worker.shutdown();
544
+ await client.close();
545
+ await pool.end();
546
+ process.exit(0);
547
+ });
548
+ ```
547
549
 
548
550
  ## Support
549
551
 
550
- - 📖 Full API documentation: [API.md](../API.md)
551
- - 🐛 Report issues: [GitHub Issues](https://github.com/Duke-Engineering/que-ts/issues)
552
- - 💬 Discussions: [GitHub Discussions](https://github.com/Duke-Engineering/que-ts/discussions)
552
+ - 📖 [Main Documentation](./README.md)
553
+ - 🔐 [SSL Configuration](./SSL.md)
554
+ - 🐛 [Issue Tracker](https://github.com/your-username/worker-que/issues)
553
555
 
554
- ## License
556
+ ---
555
557
 
556
- MIT
558
+ **Need help?** Open an issue or check the examples directory for more code samples.