¿Por qué Go es el lenguaje ideal para colas y tareas en segundo plano?
\n\nSi alguna vez ha escrito un backend en Python o Node.js, seguramente se ha enfrentado al problema: la aplicación procesa una solicitud, mientras que al mismo tiempo necesita enviar un correo, generar un informe o procesar un archivo cargado. Si se hace de forma síncrona, el usuario espera. Si se hace en un hilo separado, comienzan los bailes con bloqueos y condiciones de carrera.
\n\nGo resuelve este problema de manera elegante y nativa. Las gorutinas (goroutines) y los canales (channels) son mecanismos de concurrencia integrados que hacen que el desarrollo de colas y tareas en segundo plano en Go sea simple y seguro. En este artículo, analizaremos cómo organizar el procesamiento en segundo plano utilizando tanto la biblioteca estándar como herramientas populares como RabbitMQ. Verá ejemplos de código reales que puede aplicar inmediatamente en su proyecto.
\n\nFundamentos: gorutinas y canales
\n\nAntes de sumergirnos en las colas, recordemos lo básico. Una gorutina es un hilo de ejecución ligero que se inicia con la palabra clave go. Un canal es un "conducto" tipificado a través del cual las gorutinas se comunican entre sí.
Ejemplo simple: envío de correo electrónico asíncrono
\n\npackage main\n\nimport (\n "fmt"\n "time"\n)\n\nfunc sendEmail(email string) {\n time.Sleep(2 * time.Second) // simulación de una operación larga\n fmt.Println("Email sent to", email)\n}\n\nfunc main() {\n fmt.Println("Start")\n go sendEmail("user@example.com") // ejecución en segundo plano\n fmt.Println("Continue processing...")\n time.Sleep(3 * time.Second) // esperar a que la gorutina termine\n}\n\nAquí, sendEmail se ejecuta en segundo plano y el hilo principal no se bloquea. Pero, ¿qué pasa si necesita procesar 1000 correos? Iniciar 1000 gorutinas no es una buena idea: comenzarán a competir por los recursos. Aquí es donde los canales y el patrón Worker Pool vienen al rescate.
Patrón Worker Pool en Go
\n\nWorker Pool es un enfoque clásico para organizar colas y tareas en segundo plano en Go. Tiene un número fijo de trabajadores (gorutinas) que escuchan un solo canal de tareas. Las tareas provienen del hilo principal o de un manejador HTTP.
\n\nImplementación de Worker Pool
\n\npackage main\n\nimport (\n "fmt"\n "sync"\n "time"\n)\n\ntype Task struct {\n ID int\n Data string\n}\n\nfunc worker(id int, tasks <-chan Task, wg *sync.WaitGroup) {\n defer wg.Done()\n for task := range tasks {\n fmt.Printf("Worker %d processing task %d: %s\\n", id, task.ID, task.Data)\n time.Sleep(1 * time.Second) // simulación de trabajo\n }\n}\n\nfunc main() {\n const numWorkers = 3\n tasks := make(chan Task, 10) // canal con búfer\n\n var wg sync.WaitGroup\n\n // Iniciar trabajadores\n for i := 1; i <= numWorkers; i++ {\n wg.Add(1)\n go worker(i, tasks, &wg)\n }\n\n // Enviar tareas\n for i := 1; i <= 10; i++ {\n tasks <- Task{ID: i, Data: fmt.Sprintf("Task %d", i)}\n }\n close(tasks) // cerrar el canal para que los trabajadores terminen\n\n wg.Wait()\n fmt.Println("All tasks completed")\n}\n\nEste código crea 3 trabajadores que procesan 10 tareas. El canal con búfer permite enviar tareas sin bloqueo hasta que el búfer esté lleno. El patrón es ideal para tareas en segundo plano en Golang en aplicaciones web: recibe una solicitud, coloca la tarea en el canal y responde inmediatamente al usuario.
\n\nColas en Go con RabbitMQ
\n\nPara sistemas distribuidos, los canales en memoria no son suficientes: se necesita un almacenamiento externo de colas. RabbitMQ es uno de los intermediarios de mensajes más populares. Veamos cómo conectarlo a una aplicación Go.
\n\nInstalación y conexión
\n\nPrimero, instale la biblioteca amqp:
go get github.com/rabbitmq/amqp091-go\n\n