refactor: split worker into paid/free via WORKER_PLAN env var

Replace dual-consumer priority WorkerPool with a single consumer per
worker process. WORKER_PLAN=paid|free selects the Kafka topic and
consumer group ID (dish-recognition-paid / dish-recognition-free).

docker-compose now runs worker-paid and worker-free as separate services
for independent scaling. Makefile dev target launches both workers locally.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
dbastrikin
2026-03-19 12:11:14 +02:00
parent 1afadf50a7
commit 1aaf20619d
4 changed files with 57 additions and 61 deletions

View File

@@ -15,6 +15,7 @@ type workerConfig struct {
DatabaseURL string `envconfig:"DATABASE_URL" required:"true"`
OpenAIAPIKey string `envconfig:"OPENAI_API_KEY" required:"true"`
KafkaBrokers []string `envconfig:"KAFKA_BROKERS" default:"kafka:9092"`
WorkerPlan string `envconfig:"WORKER_PLAN" default:"free"` // "paid" | "free"
}
func loadConfig() (*workerConfig, error) {
@@ -40,19 +41,18 @@ func initWorker(workerCfg *workerConfig, pool *pgxpool.Pool) (*WorkerApp, error)
dishRepository := dish.NewRepository(pool)
jobRepository := recognition.NewJobRepository(pool)
paidConsumer, paidConsumerError := kafka.NewConsumer(
workerCfg.KafkaBrokers, "dish-recognition-workers", recognition.TopicPaid,
)
if paidConsumerError != nil {
return nil, paidConsumerError
}
freeConsumer, freeConsumerError := kafka.NewConsumer(
workerCfg.KafkaBrokers, "dish-recognition-workers", recognition.TopicFree,
)
if freeConsumerError != nil {
return nil, freeConsumerError
topic := recognition.TopicFree
groupID := "dish-recognition-free"
if workerCfg.WorkerPlan == "paid" {
topic = recognition.TopicPaid
groupID = "dish-recognition-paid"
}
workerPool := recognition.NewWorkerPool(jobRepository, openaiClient, dishRepository, paidConsumer, freeConsumer)
consumer, consumerError := kafka.NewConsumer(workerCfg.KafkaBrokers, groupID, topic)
if consumerError != nil {
return nil, consumerError
}
workerPool := recognition.NewWorkerPool(jobRepository, openaiClient, dishRepository, consumer)
return &WorkerApp{workerPool: workerPool}, nil
}