Cómo configurar Temporal.io desde cero y comprender su arquitectura a través del código usando analogías culinarias iterativas.
🚀 Introducción a Temporal
En este viaje por el ecosistema de Temporal.io, pasamos de una instalación cruda desde su código fuente original (Go) en nuestro entorno local (macOS) hasta programar todo un sistema concurrente simulando un restaurante. Aquí, Temporal asume el papel del Gerente (Coordinador), mientras el código Go de nuestra app son los Cocineros (Workers).
🛠 Configuración y Compilación desde Fuentes
En vez de instalarlo usando paquetes binarios como brew, queríamos control total. Borramos todas las huellas de instalaciones globales previas y descargamos el repositorio fuente directamente.
Apareció un reto importante: PostgreSQL local interfería, debido a que el puerto 5432 ya estaba ocupado por varias instancias de Odoo. Hicimos estas adaptaciones en los archivos fuente:
- En
develop/docker-compose/docker-compose.ymlmapeamos el puerto a5433:5432. - En
config/development-postgres12.yamlajustamos la cadena de conexión apuntando a5433. - En
Makefilesobreescribimos los comandos del inyector del esquema pasando el argumento-p 5433.
make temporal-server. Posteriormente make start-dependencies (levantando Postgres y el Frontend web en Docker) y por último, make start.
🍔 Nuestro Journey de "Hola Mundo": Fase a Fase
Fase 1: El Saludo Básico (1 Actividad Simple)
Comenzamos haciendo que nuestra aplicación de Temporal enviara un solo parámetro String y retornara un saludo. Una única Actividad llamada SaludarActivity, la cual era orquestada por su respectivo Workflow: HelloWorldWorkflow.
// Fase 1: Único paso de ejecución síncrona
func SaludarActivity(ctx context.Context, nombre string) (string, error) {
return fmt.Sprintf("¡Hola %s!", nombre), nil
}
Vimos cómo el Workflow enrutaba el "Hola Master Gero" desde nuestro start.go (Cajero) directamente al trabajador a través de una Task Queue aislada.
Fase 2: Escalando la Cocina (3 Actividades Secuenciales)
Rápidamente transformamos la analogía general introduciendo el concepto de restaurante. Modificamos nuestro Workflow para invocar 3 funciones independientes, cada una con pausas simuladas (time.Sleep):
- 🔥 Hornear el pan (2s).
- 🍖 Asar la carne (3s).
- 🍔 Ensamblar todo (1s).
El Coordinador esperaba de forma iterativa: no metía la carne a la parrilla hasta que el pan salía del horno. Temporal garantizó que todo el proceso no colapsase en medio del camino.
Fase 3: Paralelismo y Resiliencia Real (Tolerancia a Fallos)
Finalmente optimizamos el tiempo. En la Fase 3 separamos la ejecución en bloques concurrentes usando el patrón Future/Promesas de Golang: el Panadero y el Parrillero podían operar simultáneamente, permitiéndole al Workflow sincronizar sus salidas en 4s (el proceso de la carne, como embudo) y después empacar y entregar el pedido.
Pero para poner a prueba la verdadera potencia de Temporal, le inyectamos un bug intencional al panadero: configuramos que quemara el pan en sus primeros 2 intentos:
// Fase 3: Simulando desastre en 2/3 de las ejecuciones.
if info.Attempt < 3 {
return "", fmt.Errorf("Fuego, el panadero quemó el lote entero")
}
Protegimos esto usando una política inteligente (RetryPolicy) requiriendo reintentos intermitentes de 1 segundo.
🎥 El Holograma: Temporal UI en Acción
Ejecutamos nuestro workflow final y exploramos la Interfaz de UI de Temporal (localhost:8080/). A continuación tienes la grabación animada mostrando cómo la plataforma visualiza nuestra orden orden-master-gero:
Observa cómo la tarea "HornearPanActivity" repite intentos, mientras el resto de la cadena se reconstruye sola.
Lo fantástico de Temporal es que se congele todo frente al error del pan. Al corregir el código y el pan salir ileso en el tercer intento, Temporal nunca ordenó que el parrillero volviera a asar la carne, porque mantenía persistido que esa sección en paralelo ya se había guardado exitosamente. Todo reanudó justo donde debía.
🔗 Tu Propio Sandbox Compartido
Alojamos toda esta maravilla en Vauxoo. Todo este *journey* fotográfico, refactorizaciones y la configuración Docker se puede auditar aquí: