Multi-Step Process

Jorge revisando un panel de control para ver que stage han sido resueltos.

Tabla de contenidos


Problema

En sistemas distribuidos y procesos de backend, es común que una operación compleja requiera ejecutar múltiples pasos secuenciales con dependencias entre sí: creación de ficheros, subida, generación de respuestas, validación, limpieza, etc.
Controlar este flujo de estados es crítico para:

  • Garantizar que cada paso se ejecute en el orden correcto.
  • Permitir la recuperación en caso de error o reinicio del sistema.
  • Mantener la consistencia de datos incluso si el proceso se interrumpe.

Sin una estrategia clara, el código puede volverse frágil, difícil de escalar y propenso a errores.


Solución

Se implementa una función de gestión de estado por etapas que controla el avance de un ProcessModel a través de su ciclo de vida.
La idea es encapsular la lógica de transición de estado en una única función que evalúa el estado actual y ejecuta la acción correspondiente, hasta que el proceso alcanza su estado final.

El patrón se apoya en un bucle repeat-while que vuelve a evaluar el estado tras cada operación, garantizando que las transiciones ocurran de forma determinista y resiliente.

func checkProcess(
    _ process: ProcessModel
) async throws {
    var process = process
    var status = process.status

    repeat {
        status = process.status
        process = try await checkStatus(process)
    } while status != process.status
}

func checkStatus(
    _ process: ProcessModel
) async throws -> ProcessModel {
    switch process.status {
        case .filesCreated: 
            try await _uploadFiles(process)
        case .filesUploaded: 
            try await _createResponses(process)
        case .responsesCreated, .responsesReasoning: 
            try await _checkResponses(process)
        case .responsesCompleted: 
            try await _deleteFiles(process)
        case .filesDeleted: 
            try await _deleteResponses(process)
        case .responsesDeleted: 
            try await _finishResponses(process)
        case .responsesFinished: 
            try await _deleteProcess(process)
        default: process
    }
}

Claves de la implementación:

  • Centralización de estados: un único punto de control define todas las transiciones.
  • Reevaluación continua: el bucle repeat-while permite avanzar automáticamente mientras haya cambios de estado.
  • Aislamiento de operaciones: cada caso del switch delega en funciones especializadas (_uploadFiles, _createResponses, etc.), manteniendo el código limpio y testeable.

Resultado

Este patrón de gestión de procesos multi‑etapa aporta:

  • Resiliencia: cada transición es atómica y se puede reintentar si ocurre un fallo.
  • Escalabilidad: agregar nuevos pasos solo requiere añadir un nuevo caso al switch.
  • Claridad: el flujo completo del proceso se entiende con una sola lectura.

Ejemplo de aplicación: pipelines de procesamiento de datos, flujos de publicación de contenido, o cualquier proceso de larga duración que requiera control preciso de cada etapa sin comprometer la integridad de los datos.

Keep coding, keep running 🏃‍♂️