worker-que 1.0.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.
Files changed (48) hide show
  1. package/DASHBOARD-QUICKSTART.md +278 -0
  2. package/DASHBOARD.md +556 -0
  3. package/LICENSE +21 -0
  4. package/README.md +414 -0
  5. package/SSL-QUICK-REFERENCE.md +225 -0
  6. package/SSL.md +516 -0
  7. package/dist/client.d.ts +11 -0
  8. package/dist/client.d.ts.map +1 -0
  9. package/dist/client.js +64 -0
  10. package/dist/client.js.map +1 -0
  11. package/dist/dashboard/index.d.ts +34 -0
  12. package/dist/dashboard/index.d.ts.map +1 -0
  13. package/dist/dashboard/index.js +164 -0
  14. package/dist/dashboard/index.js.map +1 -0
  15. package/dist/dashboard/service.d.ts +66 -0
  16. package/dist/dashboard/service.d.ts.map +1 -0
  17. package/dist/dashboard/service.js +201 -0
  18. package/dist/dashboard/service.js.map +1 -0
  19. package/dist/dashboard/views.d.ts +3 -0
  20. package/dist/dashboard/views.d.ts.map +1 -0
  21. package/dist/dashboard/views.js +786 -0
  22. package/dist/dashboard/views.js.map +1 -0
  23. package/dist/index.d.ts +6 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +29 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/job.d.ts +19 -0
  28. package/dist/job.d.ts.map +1 -0
  29. package/dist/job.js +36 -0
  30. package/dist/job.js.map +1 -0
  31. package/dist/sql.d.ts +8 -0
  32. package/dist/sql.d.ts.map +1 -0
  33. package/dist/sql.js +57 -0
  34. package/dist/sql.js.map +1 -0
  35. package/dist/types.d.ts +90 -0
  36. package/dist/types.d.ts.map +1 -0
  37. package/dist/types.js +3 -0
  38. package/dist/types.js.map +1 -0
  39. package/dist/utils.d.ts +6 -0
  40. package/dist/utils.d.ts.map +1 -0
  41. package/dist/utils.js +31 -0
  42. package/dist/utils.js.map +1 -0
  43. package/dist/worker.d.ts +19 -0
  44. package/dist/worker.d.ts.map +1 -0
  45. package/dist/worker.js +99 -0
  46. package/dist/worker.js.map +1 -0
  47. package/migrations/schema.sql +26 -0
  48. package/package.json +105 -0
package/README.md ADDED
@@ -0,0 +1,414 @@
1
+ # que-ts
2
+
3
+ [![Test](https://github.com/Duke-Engineering/que-ts/actions/workflows/test.yml/badge.svg)](https://github.com/Duke-Engineering/que-ts/actions/workflows/test.yml)
4
+ [![Coverage](https://github.com/Duke-Engineering/que-ts/actions/workflows/coverage.yml/badge.svg)](https://github.com/Duke-Engineering/que-ts/actions/workflows/coverage.yml)
5
+ [![Security](https://github.com/Duke-Engineering/que-ts/actions/workflows/security.yml/badge.svg)](https://github.com/Duke-Engineering/que-ts/actions/workflows/security.yml)
6
+ [![npm version](https://badge.fury.io/js/que-ts.svg)](https://badge.fury.io/js/que-ts)
7
+
8
+ A TypeScript job queue library for PostgreSQL, compatible with Ruby Que and que-go implementations.
9
+
10
+ ## Features
11
+
12
+ - **Cross-language compatibility**: Works with [Que (Ruby)](https://github.com/chanks/que) and [que-go](https://github.com/bgentry/que-go) job queues
13
+ - **PostgreSQL advisory locks**: Reliable job processing with no duplicate execution
14
+ - **TypeScript support**: Full type safety with comprehensive interfaces
15
+ - **Retry logic**: Exponential backoff for failed jobs
16
+ - **Multiple queues**: Support for named queues and priorities
17
+ - **Transaction support**: Enqueue jobs within existing database transactions
18
+ - **Web Dashboard**: Real-time monitoring and management UI (Express.js integration)
19
+ - **SSL/TLS Support**: Secure connections with client certificates
20
+
21
+ ## Installation
22
+
23
+ ### From npm (when published)
24
+ ```bash
25
+ npm install que-ts
26
+ ```
27
+
28
+ ### From GitHub (development)
29
+ ```bash
30
+ npm install github:Duke-Engineering/que-ts#master
31
+ ```
32
+
33
+ **Note**: When installing from GitHub, the package will automatically build from TypeScript source using the `prepare` script.
34
+
35
+ ### Troubleshooting GitHub Installation
36
+
37
+ If you encounter "Cannot find module 'que-ts'" errors when installing from GitHub:
38
+
39
+ 1. **Check the installation completed successfully**:
40
+ ```bash
41
+ cd node_modules/que-ts
42
+ ls dist/ # Should show compiled JavaScript files
43
+ ```
44
+
45
+ 2. **Manual build if needed**:
46
+ ```bash
47
+ cd node_modules/que-ts
48
+ npm run build
49
+ ```
50
+
51
+ 3. **Verify installation**:
52
+ ```bash
53
+ cd node_modules/que-ts
54
+ node test-install.js
55
+ ```
56
+
57
+ 4. **Alternative: Use specific tag**:
58
+ ```bash
59
+ npm install github:Duke-Engineering/que-ts#v1.0.0
60
+ ```
61
+
62
+ ## Quick Start
63
+
64
+ ### Database Setup
65
+
66
+ #### Option 1: Using Docker (Recommended for Development)
67
+
68
+ ```bash
69
+ # Start PostgreSQL with Docker
70
+ npm run docker:up
71
+
72
+ # Run tests
73
+ npm test
74
+
75
+ # Stop when done
76
+ npm run docker:down
77
+ ```
78
+
79
+ For detailed Docker usage, see [DOCKER.md](DOCKER.md).
80
+
81
+ #### Option 2: Manual Database Setup
82
+
83
+ Create the required database table:
84
+
85
+ ```sql
86
+ CREATE TABLE que_jobs (
87
+ priority smallint NOT NULL DEFAULT 100,
88
+ run_at timestamptz NOT NULL DEFAULT now(),
89
+ job_id bigserial NOT NULL,
90
+ job_class text NOT NULL,
91
+ args json NOT NULL DEFAULT '[]'::json,
92
+ error_count integer NOT NULL DEFAULT 0,
93
+ last_error text,
94
+ queue text NOT NULL DEFAULT '',
95
+ PRIMARY KEY (queue, priority, run_at, job_id)
96
+ );
97
+ ```
98
+
99
+ ### Basic Usage
100
+
101
+ ```typescript
102
+ import { Client, Worker } from 'que-ts';
103
+
104
+ // Create a client
105
+ const client = new Client({
106
+ host: 'localhost',
107
+ port: 5432,
108
+ database: 'myapp',
109
+ user: 'postgres',
110
+ password: 'password'
111
+ });
112
+
113
+ // Enqueue jobs
114
+ await client.enqueue('SendEmail', ['user@example.com', 'Welcome!']);
115
+
116
+ await client.enqueue('ProcessPayment', [{ amount: 100, currency: 'USD' }], {
117
+ priority: 10,
118
+ runAt: new Date(Date.now() + 60000) // Run in 1 minute
119
+ });
120
+
121
+ // Create and start a worker
122
+ const worker = new Worker({
123
+ host: 'localhost',
124
+ port: 5432,
125
+ database: 'myapp',
126
+ user: 'postgres',
127
+ password: 'password'
128
+ });
129
+
130
+ // Register job handlers
131
+ worker.register('SendEmail', async (job) => {
132
+ const [email, message] = job.args;
133
+ console.log(`Sending email to ${email}: ${message}`);
134
+ // Email sending logic here
135
+ });
136
+
137
+ worker.register('ProcessPayment', async (job) => {
138
+ const paymentData = job.args[0];
139
+ console.log(`Processing payment of ${paymentData.amount} ${paymentData.currency}`);
140
+ // Payment processing logic here
141
+ });
142
+
143
+ // Start processing jobs
144
+ await worker.work();
145
+
146
+ // Graceful shutdown
147
+ process.on('SIGINT', async () => {
148
+ await worker.shutdown();
149
+ await client.close();
150
+ });
151
+ ```
152
+
153
+ ## Web Dashboard
154
+
155
+ que-ts includes a beautiful, real-time web dashboard for monitoring and managing your job queue.
156
+
157
+ ```typescript
158
+ import express from 'express';
159
+ import { Pool } from 'pg';
160
+ import { createDashboard } from 'que-ts/dashboard';
161
+
162
+ const app = express();
163
+ const pool = new Pool({ /* your config */ });
164
+
165
+ // Mount dashboard at /admin/queue
166
+ app.use('/admin/queue', createDashboard(pool, {
167
+ title: 'My App Queue',
168
+ refreshInterval: 3000,
169
+ auth: (req, res, next) => {
170
+ // Add your authentication logic
171
+ return req.isAuthenticated();
172
+ }
173
+ }));
174
+
175
+ app.listen(3000);
176
+ // Visit http://localhost:3000/admin/queue
177
+ ```
178
+
179
+ **Dashboard Features:**
180
+ - 📊 Real-time statistics (total, ready, scheduled, failed jobs)
181
+ - 📈 Visual analytics (charts by queue and job class)
182
+ - 🔍 Advanced filtering (status, queue, job class)
183
+ - 🔄 Job management (retry failed jobs, delete jobs)
184
+ - 🔐 Built-in authentication support
185
+ - 📱 Responsive design
186
+
187
+ For complete dashboard documentation, see [DASHBOARD.md](DASHBOARD.md).
188
+
189
+ ## SSL Configuration
190
+
191
+ For detailed SSL configuration including AWS RDS, Google Cloud SQL, Azure, and certificate setup, see [SSL.md](SSL.md).
192
+
193
+ ## API Reference
194
+
195
+ ### Client
196
+
197
+ #### Constructor
198
+
199
+ ```typescript
200
+ new Client(config?: ClientConfig)
201
+ ```
202
+
203
+ #### Methods
204
+
205
+ - `enqueue(jobClass: string, args?: any[], options?: EnqueueOptions): Promise<Job>`
206
+ - `enqueueInTx(client: PoolClient, jobClass: string, args?: any[], options?: EnqueueOptions): Promise<Job>`
207
+ - `lockJob(queue?: string): Promise<Job | null>`
208
+ - `close(): Promise<void>`
209
+
210
+ ### Worker
211
+
212
+ #### Constructor
213
+
214
+ ```typescript
215
+ new Worker(clientConfig?: ClientConfig, options?: WorkerOptions)
216
+ ```
217
+
218
+ #### Methods
219
+
220
+ - `register(jobClass: string, workFunc: WorkFunction): void`
221
+ - `work(): Promise<void>`
222
+ - `workOne(): Promise<boolean>`
223
+ - `shutdown(): Promise<void>`
224
+
225
+ ### Job
226
+
227
+ #### Properties
228
+
229
+ - `id: number`
230
+ - `queue: string`
231
+ - `priority: number`
232
+ - `runAt: Date`
233
+ - `jobClass: string`
234
+ - `args: any[]`
235
+ - `errorCount: number`
236
+ - `lastError?: string`
237
+
238
+ #### Methods
239
+
240
+ - `done(): Promise<void>`
241
+ - `delete(): Promise<void>`
242
+ - `error(errorMessage: string): Promise<void>`
243
+
244
+ ## Configuration
245
+
246
+ ### ClientConfig
247
+
248
+ ```typescript
249
+ interface ClientConfig {
250
+ connectionString?: string;
251
+ host?: string;
252
+ port?: number;
253
+ database?: string;
254
+ user?: string;
255
+ password?: string;
256
+ ssl?: boolean | SSLConfig; // See SSL Configuration below
257
+ maxConnections?: number;
258
+ }
259
+ ```
260
+
261
+ ### SSL Configuration
262
+
263
+ que-ts supports SSL/TLS connections with client certificates:
264
+
265
+ ```typescript
266
+ import { Client } from 'que-ts';
267
+ import * as fs from 'fs';
268
+
269
+ // Basic SSL
270
+ const client = new Client({
271
+ host: 'your-database.com',
272
+ port: 5432,
273
+ database: 'mydb',
274
+ user: 'myuser',
275
+ password: 'mypassword',
276
+ ssl: {
277
+ rejectUnauthorized: true,
278
+ }
279
+ });
280
+
281
+ // SSL with client certificates
282
+ const clientWithCerts = new Client({
283
+ host: 'your-database.com',
284
+ port: 5432,
285
+ database: 'mydb',
286
+ user: 'myuser',
287
+ password: 'mypassword',
288
+ ssl: {
289
+ rejectUnauthorized: true,
290
+ cert: fs.readFileSync('./certs/client-cert.pem'),
291
+ key: fs.readFileSync('./certs/client-key.pem'),
292
+ ca: fs.readFileSync('./certs/ca-cert.pem'),
293
+ passphrase: 'optional-key-passphrase', // For encrypted keys
294
+ }
295
+ });
296
+ ```
297
+
298
+ For detailed SSL configuration including AWS RDS, Google Cloud SQL, Azure, and certificate setup, see [SSL.md](SSL.md).
299
+
300
+ ### WorkerOptions
301
+
302
+ ```typescript
303
+ interface WorkerOptions {
304
+ queue?: string; // Queue name to process (default: '')
305
+ interval?: number; // Polling interval in ms (default: 5000)
306
+ maxAttempts?: number; // Max retry attempts (default: 5)
307
+ }
308
+ ```
309
+
310
+ ### EnqueueOptions
311
+
312
+ ```typescript
313
+ interface EnqueueOptions {
314
+ priority?: number; // Job priority (lower = higher priority, default: 100)
315
+ runAt?: Date; // When to run the job (default: now)
316
+ queue?: string; // Queue name (default: '')
317
+ }
318
+ ```
319
+
320
+ ## Error Handling and Retries
321
+
322
+ Failed jobs are automatically retried with exponential backoff:
323
+
324
+ - 1st retry: after 1 second
325
+ - 2nd retry: after 16 seconds
326
+ - 3rd retry: after 81 seconds
327
+ - 4th retry: after 256 seconds
328
+ - etc.
329
+
330
+ Jobs that exceed the maximum number of retries remain in the queue for manual inspection.
331
+
332
+ ## Queues and Priorities
333
+
334
+ Jobs can be organized into named queues and assigned priorities:
335
+
336
+ ```typescript
337
+ // High priority job in 'critical' queue
338
+ await client.enqueue('ProcessPayment', [paymentData], {
339
+ queue: 'critical',
340
+ priority: 1
341
+ });
342
+
343
+ // Low priority job in 'background' queue
344
+ await client.enqueue('SendNewsletter', [newsletterData], {
345
+ queue: 'background',
346
+ priority: 500
347
+ });
348
+
349
+ // Worker processing only critical queue
350
+ const criticalWorker = new Worker(config, { queue: 'critical' });
351
+ ```
352
+
353
+ ## Cross-Language Compatibility
354
+
355
+ que-ts is designed to be fully compatible with:
356
+
357
+ - **[Ruby Que](https://github.com/chanks/que)** - The original Ruby implementation
358
+ - **[que-go](https://github.com/bgentry/que-go)** - Golang port (currently unmaintained)
359
+
360
+ You can enqueue jobs in one language and process them in another, or run workers in multiple languages simultaneously.
361
+
362
+ ## Related Projects
363
+
364
+ ### Official Implementations
365
+ - **[Que (Ruby)](https://github.com/chanks/que)** - The original and most mature implementation
366
+ - **[que-go](https://github.com/bgentry/que-go)** - Go implementation (unmaintained, but stable)
367
+ - **[que-ts](https://github.com/Duke-Engineering/que-ts)** - This TypeScript/Node.js implementation
368
+
369
+ ## Development
370
+
371
+ ### Using Docker (Recommended)
372
+
373
+ ```bash
374
+ # Install dependencies
375
+ npm install
376
+
377
+ # Start PostgreSQL with Docker
378
+ npm run docker:up
379
+
380
+ # Run tests
381
+ npm test
382
+
383
+ # Run tests in watch mode
384
+ npm run test:watch
385
+
386
+ # Build
387
+ npm run build
388
+
389
+ # Lint
390
+ npm run lint
391
+
392
+ # Stop Docker containers
393
+ npm run docker:down
394
+ ```
395
+
396
+ ### Docker Commands
397
+
398
+ - `npm run docker:up` - Start PostgreSQL and Adminer
399
+ - `npm run docker:down` - Stop containers
400
+ - `npm run docker:logs` - View PostgreSQL logs
401
+ - `npm run docker:clean` - Remove containers and volumes
402
+ - `npm run test:docker` - Full test cycle with Docker
403
+
404
+ Access database admin at http://localhost:8080 (user: `que_user`, password: `que_password`)
405
+
406
+ See [DOCKER.md](DOCKER.md) for detailed Docker documentation.
407
+
408
+ ### Manual Setup
409
+
410
+ If you prefer not to use Docker, ensure PostgreSQL is running and create the database schema manually using `migrations/schema.sql`.
411
+
412
+ ## License
413
+
414
+ MIT
@@ -0,0 +1,225 @@
1
+ # SSL Quick Reference
2
+
3
+ ## Quick SSL Setup Examples
4
+
5
+ ### 1. Basic SSL (No Certificates)
6
+
7
+ ```typescript
8
+ import { Client } from 'que-ts';
9
+
10
+ const client = new Client({
11
+ host: 'db.example.com',
12
+ port: 5432,
13
+ database: 'mydb',
14
+ user: 'myuser',
15
+ password: 'mypass',
16
+ ssl: { rejectUnauthorized: true }
17
+ });
18
+ ```
19
+
20
+ ### 2. SSL with Client Certificates
21
+
22
+ ```typescript
23
+ import * as fs from 'fs';
24
+
25
+ const client = new Client({
26
+ host: 'db.example.com',
27
+ port: 5432,
28
+ database: 'mydb',
29
+ user: 'myuser',
30
+ password: 'mypass',
31
+ ssl: {
32
+ rejectUnauthorized: true,
33
+ cert: fs.readFileSync('./client-cert.pem'),
34
+ key: fs.readFileSync('./client-key.pem'),
35
+ ca: fs.readFileSync('./ca-cert.pem'),
36
+ }
37
+ });
38
+ ```
39
+
40
+ ### 3. Using Environment Variables
41
+
42
+ ```typescript
43
+ // .env file:
44
+ // DB_SSL_CERT=/path/to/client-cert.pem
45
+ // DB_SSL_KEY=/path/to/client-key.pem
46
+ // DB_SSL_CA=/path/to/ca-cert.pem
47
+
48
+ import * as fs from 'fs';
49
+ import * as dotenv from 'dotenv';
50
+ dotenv.config();
51
+
52
+ const client = new Client({
53
+ host: process.env.DB_HOST,
54
+ port: parseInt(process.env.DB_PORT || '5432'),
55
+ database: process.env.DB_NAME,
56
+ user: process.env.DB_USER,
57
+ password: process.env.DB_PASSWORD,
58
+ ssl: {
59
+ rejectUnauthorized: true,
60
+ cert: fs.readFileSync(process.env.DB_SSL_CERT!),
61
+ key: fs.readFileSync(process.env.DB_SSL_KEY!),
62
+ ca: fs.readFileSync(process.env.DB_SSL_CA!),
63
+ }
64
+ });
65
+ ```
66
+
67
+ ## Cloud Providers
68
+
69
+ ### AWS RDS
70
+
71
+ ```typescript
72
+ // Download CA bundle: https://truststore.pki.rds.amazonaws.com/global/global-bundle.pem
73
+ const client = new Client({
74
+ host: 'instance.region.rds.amazonaws.com',
75
+ ssl: {
76
+ rejectUnauthorized: true,
77
+ ca: fs.readFileSync('./rds-ca-bundle.pem'),
78
+ }
79
+ });
80
+ ```
81
+
82
+ ### Google Cloud SQL
83
+
84
+ ```typescript
85
+ const client = new Client({
86
+ host: 'instance-ip',
87
+ ssl: {
88
+ rejectUnauthorized: true,
89
+ ca: fs.readFileSync('./server-ca.pem'),
90
+ cert: fs.readFileSync('./client-cert.pem'),
91
+ key: fs.readFileSync('./client-key.pem'),
92
+ }
93
+ });
94
+ ```
95
+
96
+ ### Azure PostgreSQL
97
+
98
+ ```typescript
99
+ // Download cert: https://learn.microsoft.com/en-us/azure/postgresql/
100
+ const client = new Client({
101
+ host: 'server.postgres.database.azure.com',
102
+ user: 'user@server',
103
+ ssl: {
104
+ rejectUnauthorized: true,
105
+ ca: fs.readFileSync('./BaltimoreCyberTrustRoot.crt.pem'),
106
+ }
107
+ });
108
+ ```
109
+
110
+ ### Heroku Postgres
111
+
112
+ ```typescript
113
+ const client = new Client({
114
+ connectionString: process.env.DATABASE_URL,
115
+ ssl: { rejectUnauthorized: false } // Heroku uses self-signed
116
+ });
117
+ ```
118
+
119
+ ## Certificate File Permissions
120
+
121
+ ```bash
122
+ chmod 600 client-key.pem # Private key (read/write owner only)
123
+ chmod 644 client-cert.pem # Certificate (readable by all)
124
+ chmod 644 ca-cert.pem # CA certificate (readable by all)
125
+ ```
126
+
127
+ ## Generate Self-Signed Certificates (Dev/Testing)
128
+
129
+ ```bash
130
+ # CA certificate
131
+ openssl req -new -x509 -days 365 -nodes -text \
132
+ -out ca-cert.pem -keyout ca-key.pem
133
+
134
+ # Client certificate and key
135
+ openssl req -new -nodes -text \
136
+ -out client.csr -keyout client-key.pem
137
+
138
+ openssl x509 -req -in client.csr -text -days 365 \
139
+ -CA ca-cert.pem -CAkey ca-key.pem -CAcreateserial \
140
+ -out client-cert.pem
141
+ ```
142
+
143
+ ## Troubleshooting
144
+
145
+ | Error | Solution |
146
+ |-------|----------|
147
+ | "self signed certificate" | Add `ca` certificate or set `rejectUnauthorized: false` (dev only) |
148
+ | "unable to verify first certificate" | Include complete certificate chain in `ca` |
149
+ | "certificate has expired" | Renew certificates |
150
+ | "ENOENT: no such file" | Check file paths are correct and files exist |
151
+
152
+ ## Test SSL Connection
153
+
154
+ ```typescript
155
+ async function testConnection() {
156
+ const client = new Client({
157
+ host: 'your-host',
158
+ ssl: {
159
+ rejectUnauthorized: true,
160
+ cert: fs.readFileSync('./client-cert.pem'),
161
+ key: fs.readFileSync('./client-key.pem'),
162
+ ca: fs.readFileSync('./ca-cert.pem'),
163
+ }
164
+ });
165
+
166
+ try {
167
+ const job = await client.enqueue('Test', []);
168
+ console.log('✓ Connected! Job ID:', job.id);
169
+ await client.close();
170
+ } catch (err) {
171
+ console.error('✗ Failed:', err.message);
172
+ }
173
+ }
174
+ ```
175
+
176
+ ## Security Checklist
177
+
178
+ - [ ] Use `rejectUnauthorized: true` in production
179
+ - [ ] Never commit certificates to git
180
+ - [ ] Use environment variables for paths/secrets
181
+ - [ ] Set correct file permissions (600 for keys)
182
+ - [ ] Rotate certificates regularly
183
+ - [ ] Use strong key passphrases
184
+ - [ ] Add `*.pem`, `*.key`, `*.crt` to `.gitignore`
185
+
186
+ ## Complete Example
187
+
188
+ ```typescript
189
+ // config.ts
190
+ import { Client, SSLConfig } from 'que-ts';
191
+ import * as fs from 'fs';
192
+
193
+ export function createSecureClient(): Client {
194
+ const sslConfig: SSLConfig = {
195
+ rejectUnauthorized: true,
196
+ cert: fs.readFileSync(process.env.DB_SSL_CERT || './certs/client-cert.pem'),
197
+ key: fs.readFileSync(process.env.DB_SSL_KEY || './certs/client-key.pem'),
198
+ ca: fs.readFileSync(process.env.DB_SSL_CA || './certs/ca-cert.pem'),
199
+ };
200
+
201
+ return new Client({
202
+ host: process.env.DB_HOST || 'localhost',
203
+ port: parseInt(process.env.DB_PORT || '5432'),
204
+ database: process.env.DB_NAME || 'mydb',
205
+ user: process.env.DB_USER || 'postgres',
206
+ password: process.env.DB_PASSWORD,
207
+ ssl: process.env.NODE_ENV === 'production' ? sslConfig : false,
208
+ maxConnections: 10,
209
+ });
210
+ }
211
+
212
+ // usage.ts
213
+ import { createSecureClient } from './config';
214
+
215
+ const client = createSecureClient();
216
+
217
+ async function main() {
218
+ await client.enqueue('SendEmail', ['user@example.com']);
219
+ await client.close();
220
+ }
221
+ ```
222
+
223
+ ---
224
+
225
+ For full documentation, see [SSL.md](SSL.md)