Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x | /**
* Queue Configuration
*
* Configures BullMQ queues with Redis connection settings.
* Supports both Redis (production) and in-memory fallback (development).
*/
import { ConnectionOptions, DefaultJobOptions } from 'bullmq';
/**
* Redis connection settings extracted for direct access
*/
const redisConfig = {
host: process.env.REDIS_HOST || 'localhost',
port: parseInt(process.env.REDIS_PORT || '6379', 10),
password: process.env.REDIS_PASSWORD || undefined,
};
/**
* Redis connection configuration for BullMQ
* Uses environment variables for production, defaults for development
*/
export const redisConnection: ConnectionOptions = {
...redisConfig,
maxRetriesPerRequest: null, // Required for BullMQ
enableReadyCheck: false,
retryStrategy: (times: number) => {
// Stop retrying after 5 attempts in development
if (process.env.NODE_ENV === 'development' && times > 5) {
return null;
}
// Exponential backoff with max 30 seconds
return Math.min(times * 1000, 30000);
},
};
/**
* Check if Redis is available
*/
export async function isRedisAvailable(): Promise<boolean> {
if (process.env.SKIP_REDIS === 'true') {
return false;
}
try {
const { Redis } = await import('ioredis');
const client = new Redis({
host: redisConfig.host,
port: redisConfig.port,
password: redisConfig.password,
lazyConnect: true,
connectTimeout: 3000,
});
await client.connect();
await client.ping();
await client.quit();
return true;
} catch {
return false;
}
}
/**
* Queue configurations
*/
export const queueConfig = {
email: {
name: 'email-queue',
defaultJobOptions: {
attempts: 3,
backoff: {
type: 'exponential' as const,
delay: 1000,
},
removeOnComplete: {
age: 24 * 3600, // 24 hours
count: 1000,
},
removeOnFail: {
age: 7 * 24 * 3600, // 7 days
},
} satisfies DefaultJobOptions,
},
notification: {
name: 'notification-queue',
defaultJobOptions: {
attempts: 2,
backoff: {
type: 'fixed' as const,
delay: 5000,
},
removeOnComplete: {
age: 3600, // 1 hour
count: 500,
},
} satisfies DefaultJobOptions,
},
};
/**
* Rate limiting configuration (per minute)
*/
export const rateLimits = {
email: {
max: 100, // Max 100 emails per duration
duration: 60000, // Per minute
},
notification: {
max: 200,
duration: 60000,
},
};
/**
* Worker concurrency settings
*/
export const workerConcurrency = {
email: parseInt(process.env.EMAIL_WORKER_CONCURRENCY || '5', 10),
notification: parseInt(process.env.NOTIFICATION_WORKER_CONCURRENCY || '10', 10),
};
|