--- name: job_worker_pool kind: function lang: go domain: infra version: "1.0.0" purity: impure signature: "func JobWorkerPool(ctx context.Context, q *JobQueue, n int, handler JobHandler, opts ...WorkerOption) error" description: "Lanza n workers concurrentes que comparten la misma cola y handler. Usa errgroup para concurrencia estructurada y soporta graceful shutdown via context. Bloquea hasta que todos los workers terminen." tags: [job, queue, worker, pool, concurrency, errgroup, async, background, infra, graceful-shutdown] uses_functions: [job_worker_go_infra] uses_types: [job_queue_go_infra] returns: [] returns_optional: false error_type: "error_go_core" imports: [context, fmt, golang.org/x/sync/errgroup] params: - name: ctx desc: "context que al cancelarse detiene todos los workers; si uno falla, los demas tambien se detienen" - name: q desc: "cola de jobs compartida por todos los workers" - name: n desc: "numero de workers concurrentes (debe ser > 0)" - name: handler desc: "funcion de procesamiento compartida por todos los workers" - name: opts desc: "opciones aplicadas a cada worker: WithPollInterval, WithJobTypes" output: "primer error no-context de cualquier worker, o ctx.Err() si todos terminaron por cancelacion" tested: true tests: - "concurrency_multiples_goroutines_dequeue" test_file_path: "functions/infra/job_queue_test.go" file_path: "functions/infra/job_worker_pool.go" --- ## Ejemplo ```go ctx, cancel := context.WithCancel(context.Background()) defer cancel() // 5 workers procesando emails en paralelo err := JobWorkerPool(ctx, q, 5, func(job Job) error { return sendEmail(job) }, WithPollInterval(100*time.Millisecond)) ``` ## Notas Usa `golang.org/x/sync/errgroup`. Si un worker retorna un error no-context, `errgroup` cancela el context derivado y todos los demas workers se detienen. El graceful shutdown ocurre al cancelar el context original.