package main import ( "context" "errors" "os/signal" "strings" "syscall" queueapp "wucher/internal/app/queueing" appworker "wucher/internal/app/worker" "wucher/internal/config" "wucher/internal/queue" mysqlrepo "wucher/internal/repository/mysql" s3repo "wucher/internal/repository/s3" "wucher/internal/resilience" "wucher/internal/service" "wucher/internal/shared/pkg/logger" ) func runFileWorker(appCfg config.AppConfig) error { ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM) defer stop() appLogger := logger.New(appCfg.Logging).With("component", "worker", "job", "file_processing") resCfg := appCfg.Resilience fileQueueCfg := appCfg.FileQueue fileSQSCfg := appCfg.FileSQS if err := config.ValidateDistinctQueueURLs(appCfg.SQS, fileSQSCfg); err != nil { return err } if strings.TrimSpace(fileSQSCfg.QueueURL) == "" { return errors.New("FILE_SQS_QUEUE_URL is required for file worker") } db, err := mysqlrepo.Connect(appCfg.MySQL) if err != nil { return err } fileRepo := mysqlrepo.NewFileManagerFileRepository(db) sqsBreaker := resilience.NewExecutor("sqs", resCfg.SQS, appLogger, resilience.ClassifySQSError) consumer, serializer, err := queueapp.NewFileProcessingConsumer(ctx, fileQueueCfg, fileSQSCfg, sqsBreaker) if err != nil { return err } idempotency := queueapp.NewIdempotencyStoreWithPrefix(db, fileQueueCfg.IdempotencyKeyPrefix) useCaseDeps := service.FileProcessingUseCaseDependencies{ Logger: appLogger, FileStatusEvents: fileRepo, GotenbergURL: appCfg.Gotenberg.URL, } fileStorageCfg := appCfg.FileStorage if fileStorageCfg.Bucket != "" && fileStorageCfg.Region != "" { storage, err := s3repo.NewFileObjectStorage(ctx, fileStorageCfg) if err != nil { return err } useCaseDeps.Storage = storage } useCase := service.NewFileProcessingUseCase(fileRepo, useCaseDeps) handler := queue.NewFileProcessingJobQueueHandler(useCase, service.IsFileProcessingPermanentError) var dispatcher *appworker.FileProcessingOutboxDispatcher if fileQueueCfg.OutboxEnabled { rawProducer, err := queueapp.NewQueueProducer(ctx, fileSQSCfg, sqsBreaker, "outbox_dispatcher") if err != nil { return err } dispatcher = appworker.NewFileProcessingOutboxDispatcher(fileQueueCfg, fileRepo, rawProducer, appLogger) } runner := appworker.NewFileProcessingRunner(fileQueueCfg, consumer, serializer, handler, idempotency, dispatcher, appLogger) appLogger.Info("file worker started", "backend", "sqs", "monitor_addr", fileQueueCfg.WorkerMonitorAddr, "queue_url", fileSQSCfg.QueueURL, "outbox_enabled", fileQueueCfg.OutboxEnabled, ) if err := runner.Start(ctx); err != nil { return err } appLogger.Info("file worker stopped") return nil }