DB refactor for easier testsing
Some checks failed
Deploy to Web Server flyer-crawler.projectium.com / deploy (push) Failing after 5m16s
Some checks failed
Deploy to Web Server flyer-crawler.projectium.com / deploy (push) Failing after 5m16s
App.ts refactor into hooks unit tests
This commit is contained in:
@@ -11,6 +11,7 @@ import { aiService } from './aiService.server';
|
||||
import * as emailService from './emailService.server';
|
||||
import * as db from './db/index.db';
|
||||
import { FlyerProcessingService, type FlyerJobData, type IFileSystem } from './flyerProcessingService.server';
|
||||
import { FlyerDataTransformer } from './flyerDataTransformer';
|
||||
|
||||
// --- Start: Interfaces for Dependency Injection ---
|
||||
// --- End: Interfaces for Dependency Injection ---
|
||||
@@ -68,6 +69,19 @@ export const analyticsQueue = new Queue<AnalyticsJobData>('analytics-reporting',
|
||||
},
|
||||
});
|
||||
|
||||
export const weeklyAnalyticsQueue = new Queue<WeeklyAnalyticsJobData>('weekly-analytics-reporting', {
|
||||
connection,
|
||||
defaultJobOptions: {
|
||||
attempts: 2,
|
||||
backoff: {
|
||||
type: 'exponential',
|
||||
delay: 3600000, // 1 hour delay for retries
|
||||
},
|
||||
removeOnComplete: true,
|
||||
removeOnFail: 50,
|
||||
},
|
||||
});
|
||||
|
||||
export const cleanupQueue = new Queue<CleanupJobData>('file-cleanup', {
|
||||
connection,
|
||||
defaultJobOptions: {
|
||||
@@ -95,6 +109,14 @@ interface AnalyticsJobData {
|
||||
reportDate: string; // e.g., '2024-10-26'
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the data for a weekly analytics job.
|
||||
*/
|
||||
interface WeeklyAnalyticsJobData {
|
||||
reportYear: number;
|
||||
reportWeek: number; // ISO week number (1-53)
|
||||
}
|
||||
|
||||
interface CleanupJobData {
|
||||
flyerId: number;
|
||||
// An array of absolute file paths to be deleted. Made optional for manual cleanup triggers.
|
||||
@@ -115,7 +137,8 @@ const flyerProcessingService = new FlyerProcessingService(
|
||||
db,
|
||||
fsAdapter,
|
||||
execAsync,
|
||||
cleanupQueue // Inject the cleanup queue to break the circular dependency
|
||||
cleanupQueue, // Inject the cleanup queue to break the circular dependency
|
||||
new FlyerDataTransformer() // Inject the new transformer
|
||||
);
|
||||
|
||||
/**
|
||||
@@ -154,9 +177,12 @@ export const emailWorker = new Worker<EmailJobData>(
|
||||
try {
|
||||
await emailService.sendEmail(job.data);
|
||||
} catch (error: unknown) {
|
||||
const errorMessage = error instanceof Error ? error.message : 'An unknown email error occurred';
|
||||
// Standardize error logging to capture the full error object, including the stack trace.
|
||||
// This provides more context for debugging than just logging the message.
|
||||
logger.error(`[EmailWorker] Job ${job.id} failed. Attempt ${job.attemptsMade}/${job.opts.attempts}.`, {
|
||||
error: errorMessage,
|
||||
// Log the full error object for better diagnostics.
|
||||
error: error instanceof Error ? error : new Error(String(error)),
|
||||
// Also include the job data for context.
|
||||
jobData: job.data,
|
||||
});
|
||||
// Re-throw to let BullMQ handle the failure and retry.
|
||||
@@ -189,9 +215,9 @@ export const analyticsWorker = new Worker<AnalyticsJobData>(
|
||||
await new Promise(resolve => setTimeout(resolve, 10000)); // Simulate a 10-second task
|
||||
logger.info(`[AnalyticsWorker] Successfully generated report for ${reportDate}.`);
|
||||
} catch (error: unknown) {
|
||||
const errorMessage = error instanceof Error ? error.message : 'An unknown analytics error occurred';
|
||||
// Standardize error logging.
|
||||
logger.error(`[AnalyticsWorker] Job ${job.id} failed. Attempt ${job.attemptsMade}/${job.opts.attempts}.`, {
|
||||
error: errorMessage,
|
||||
error: error instanceof Error ? error : new Error(String(error)),
|
||||
jobData: job.data,
|
||||
});
|
||||
throw error; // Re-throw to let BullMQ handle the failure and retry.
|
||||
@@ -238,8 +264,10 @@ export const cleanupWorker = new Worker<CleanupJobData>(
|
||||
}
|
||||
logger.info(`[CleanupWorker] Successfully cleaned up ${paths.length} file(s) for flyer ${flyerId}.`);
|
||||
} catch (error: unknown) {
|
||||
const errorMessage = error instanceof Error ? error.message : 'An unknown cleanup error occurred';
|
||||
logger.error(`[CleanupWorker] Job ${job.id} for flyer ${flyerId} failed. Attempt ${job.attemptsMade}/${job.opts.attempts}.`, { error: errorMessage });
|
||||
// Standardize error logging.
|
||||
logger.error(`[CleanupWorker] Job ${job.id} for flyer ${flyerId} failed. Attempt ${job.attemptsMade}/${job.opts.attempts}.`, {
|
||||
error: error instanceof Error ? error : new Error(String(error)),
|
||||
});
|
||||
throw error; // Re-throw to let BullMQ handle the failure and retry.
|
||||
}
|
||||
},
|
||||
@@ -249,11 +277,40 @@ export const cleanupWorker = new Worker<CleanupJobData>(
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* A dedicated worker for generating weekly analytics reports.
|
||||
* This is a placeholder for the actual report generation logic.
|
||||
*/
|
||||
export const weeklyAnalyticsWorker = new Worker<WeeklyAnalyticsJobData>(
|
||||
'weekly-analytics-reporting',
|
||||
async (job: Job<WeeklyAnalyticsJobData>) => {
|
||||
const { reportYear, reportWeek } = job.data;
|
||||
logger.info(`[WeeklyAnalyticsWorker] Starting weekly report generation for job ${job.id}`, { reportYear, reportWeek });
|
||||
try {
|
||||
// Simulate a longer-running task for weekly reports
|
||||
await new Promise(resolve => setTimeout(resolve, 30000)); // Simulate 30-second task
|
||||
logger.info(`[WeeklyAnalyticsWorker] Successfully generated weekly report for week ${reportWeek}, ${reportYear}.`);
|
||||
} catch (error: unknown) {
|
||||
// Standardize error logging.
|
||||
logger.error(`[WeeklyAnalyticsWorker] Job ${job.id} failed. Attempt ${job.attemptsMade}/${job.opts.attempts}.`, {
|
||||
error: error instanceof Error ? error : new Error(String(error)),
|
||||
jobData: job.data,
|
||||
});
|
||||
throw error; // Re-throw to let BullMQ handle the failure and retry.
|
||||
}
|
||||
},
|
||||
{
|
||||
connection,
|
||||
concurrency: parseInt(process.env.WEEKLY_ANALYTICS_WORKER_CONCURRENCY || '1', 10),
|
||||
}
|
||||
);
|
||||
|
||||
// --- Attach Event Listeners to All Workers ---
|
||||
attachWorkerEventListeners(flyerWorker);
|
||||
attachWorkerEventListeners(emailWorker);
|
||||
attachWorkerEventListeners(analyticsWorker);
|
||||
attachWorkerEventListeners(cleanupWorker);
|
||||
attachWorkerEventListeners(weeklyAnalyticsWorker);
|
||||
|
||||
logger.info('All workers started and listening for jobs.');
|
||||
|
||||
|
||||
Reference in New Issue
Block a user