Fix Docker build and production server infrastructure
- Add SKIP_ENV_VALIDATION to bypass Zod env check during next build - Bundle custom server.ts with esbuild so production uses Socket.io - Create worker entry point (src/worker.ts) with all BullMQ workers - Add esbuild build scripts for server and worker bundles - Fix Dockerfile.worker to include its own build stage - Fix pre-commit hook to work without global pnpm - Add CLAUDE.md with project conventions and quick reference Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -52,6 +52,10 @@ const envSchema = z.object({
|
||||
export type Env = z.infer<typeof envSchema>;
|
||||
|
||||
function validateEnv(): Env {
|
||||
if (process.env.SKIP_ENV_VALIDATION === '1') {
|
||||
return process.env as unknown as Env;
|
||||
}
|
||||
|
||||
const result = envSchema.safeParse(process.env);
|
||||
if (!result.success) {
|
||||
console.error('Invalid environment variables:');
|
||||
|
||||
43
src/worker.ts
Normal file
43
src/worker.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* Worker entry point for the crm-worker container.
|
||||
*
|
||||
* Imports all BullMQ workers and registers recurring job schedules.
|
||||
* In production this runs as a separate process (Dockerfile.worker).
|
||||
* In development, server.ts imports workers inline instead.
|
||||
*/
|
||||
|
||||
import { logger } from '@/lib/logger';
|
||||
import { registerRecurringJobs } from '@/lib/queue/scheduler';
|
||||
|
||||
// Import all workers — the act of importing starts them
|
||||
import { emailWorker } from '@/lib/queue/workers/email';
|
||||
import { documentsWorker } from '@/lib/queue/workers/documents';
|
||||
import { notificationsWorker } from '@/lib/queue/workers/notifications';
|
||||
import { importWorker } from '@/lib/queue/workers/import';
|
||||
import { exportWorker } from '@/lib/queue/workers/export';
|
||||
|
||||
// Keep references so workers aren't GC'd
|
||||
const workers = [emailWorker, documentsWorker, notificationsWorker, importWorker, exportWorker];
|
||||
|
||||
async function main(): Promise<void> {
|
||||
logger.info({ workerCount: workers.length }, 'BullMQ workers started');
|
||||
|
||||
await registerRecurringJobs();
|
||||
logger.info('Recurring jobs registered');
|
||||
|
||||
// Graceful shutdown
|
||||
const shutdown = async () => {
|
||||
logger.info('Shutting down workers...');
|
||||
await Promise.all(workers.map((w) => w.close()));
|
||||
logger.info('All workers closed');
|
||||
process.exit(0);
|
||||
};
|
||||
|
||||
process.on('SIGTERM', shutdown);
|
||||
process.on('SIGINT', shutdown);
|
||||
}
|
||||
|
||||
main().catch((err) => {
|
||||
logger.error(err, 'Worker process failed to start');
|
||||
process.exit(1);
|
||||
});
|
||||
Reference in New Issue
Block a user