Async Task List

Jorge participando en las distintas pruebas de una Decatlón y checkeando las realizadas.

Tabla de contenidos


Problema

En sistemas distribuidos con microservicios, un proceso complejo puede generar dificultades de control y fiabilidad. Una solución es dividirlo en tareas atómicas, lo que permite un control más granular del flujo, mejorar la observabilidad, asegurar la idempotencia y facilitar la recuperación ante fallos.

El reto es diseñar un patrón que permita una degradación controlada, de modo que el fallo de una tarea no afecte al flujo completo, garantizando resiliencia y tolerancia a fallos en entornos de producción.


Solución

Crear un task executor que orquesta tareas asíncronas.
La función execute envuelve cada tarea, gestiona errores con do-catch como circuit breaker, actualiza el estado en caso de éxito, registra y persiste los fallos, y asegura una transacción atómica para mantener la consistencia de datos.

func execute(
    status: StatusEnum,
    process: ProcessModel,
    _ work: () async throws -> ProcessModel
) async throws {
    do {
        let job = try await work()
        process.setStatus(job.status)
    } catch {
        process.setError(type: status, message: "\(error)")
    }
    try await repo.updateProcess(process)
}

Resultado

Esta implementación ofrece una abstracción de alto nivel que permite una orquestación precisa de procesos asíncronos complejos con garantías de atomicidad y durabilidad.

🎯 Separation of Concerns: cada tarea aísla su contexto de ejecución y su gestión de errores.

🔄 Workflow Orchestration: posibilita encadenar tareas mediante el pipeline pattern.

📊 Observability: genera un audit trail completo para depuración y monitorización.

Performance: mantiene alta concurrencia sin comprometer la consistencia de datos.

🛡️ Resilience: incorpora fail-fast y recovery patterns automáticos.

try await execute(status: .loadImages, process: process) {
    // Your implementation
}

Keep coding, keep running 🏃‍♂️