Los trabajos asíncronos permiten desacoplar importaciones, sincronizaciones, notificaciones, generación de documentos e integraciones. Sin embargo, que un consumidor haya procesado un mensaje no demuestra necesariamente que el resultado de negocio sea correcto. Puede haberse registrado un éxito antes de confirmar un efecto externo, haberse producido una caída entre dos pasos o haberse ejecutado la misma operación más de una vez.
La reconciliación de trabajos asíncronos en PHP cubre esa diferencia: compara lo que el sistema esperaba conseguir con la evidencia de lo que ocurrió, detecta ausencias o discrepancias y activa una corrección controlada. No sustituye a la cola, a los reintentos ni a la idempotencia; los completa con una verificación independiente.
Una ejecución técnica no equivale a un resultado de negocio

Una tarea puede terminar sin una excepción y, aun así, dejar un proceso incompleto. Por ejemplo, una aplicación crea una solicitud de sincronización, el consumidor llama a una API externa y recibe una respuesta no concluyente por un corte de red. Si reintenta sin una clave idempotente, puede crear un duplicado. Si asume el éxito, puede dejar el registro sin sincronizar.
Tampoco debe darse por sentada una semántica de entrega concreta de la infraestructura de mensajería. La posibilidad de redeliveries y ejecuciones duplicadas depende del broker, su configuración de persistencia, los reconocimientos, el comportamiento del consumidor y los fallos que se produzcan. El diseño debe verificar estas propiedades en la tecnología elegida y, cuando puedan ocurrir duplicados o reordenamientos, tolerarlos explícitamente.
La pregunta operativa no es solo «¿se consumió el mensaje?», sino «¿puedo demostrar que el efecto esperado existe, una sola vez cuando corresponda, y con los datos correctos?». Esa demostración requiere una fuente de evidencia: una respuesta consultable del sistema externo, un identificador remoto persistido, un documento almacenado o un cambio de estado confirmado.
Reintentos, idempotencia y reconciliación: responsabilidades distintas
Los reintentos tratan errores transitorios: indisponibilidad temporal, límites de uso, bloqueos breves o problemas de red. Conviene definir límite de intentos, demora progresiva, clasificación de errores y destino para mensajes que necesitan atención. Reintentar indefinidamente puede ocultar un error de datos o agravar una incidencia externa.
La idempotencia hace seguro repetir una operación. Puede lograrse con un identificador estable de operación enviado a un proveedor externo, una restricción única en base de datos, o una comprobación transaccional previa al efecto. No significa que el efecto se haya producido: significa que una repetición no debería multiplicarlo.
La reconciliación busca operaciones pendientes, incompletas o contradictorias y decide qué hacer con cada una. Es especialmente necesaria cuando hay efectos externos, procesos por lotes, actualizaciones de varios sistemas o comunicaciones cuya recepción no puede probarse solo desde la aplicación emisora.
- Use reintentos para volver a intentar fallos clasificados como transitorios.
- Use idempotencia para impedir que los reintentos o redeliveries dupliquen efectos.
- Use reconciliación para comprobar el estado final y reparar diferencias detectadas.
Modelar la operación y conservar evidencia verificable
Un diseño mantenible separa tres conceptos. El trabajo solicitado representa la intención, por ejemplo, «sincronizar el pedido 452». El efecto esperado define el resultado observable: «el sistema externo contiene el pedido con la versión 7». La confirmación almacena la evidencia de que dicho resultado existe: identificador remoto, versión, marca temporal, respuesta validada o resultado de una consulta posterior.
Antes de publicar un mensaje, cree un registro de ejecución en una base de datos duradera. Si la aplicación modifica datos propios y publica un mensaje, considere el patrón outbox: guarde el cambio de negocio y el evento pendiente en la misma transacción, y delegue la publicación a un proceso posterior. Así se reduce el riesgo de confirmar el cambio local y perder el mensaje, o publicar un mensaje para un cambio que se revirtió.
El registro debe incluir, como mínimo:
- operation_id inmutable y único, usado para correlacionar mensajes, logs y llamadas externas.
- Tipo de operación, entidad afectada y versión o huella del contenido esperado.
- Estado actual, número de intentos, siguiente intento permitido y marcas temporales.
- Clave idempotente y, si existe, identificador del recurso remoto.
- Evidencia resumida y referencias seguras a respuestas o errores, sin registrar secretos ni datos personales innecesarios.
- Motivo de cierre, compensación, descarte o escalado a revisión humana.
Defina transiciones explícitas, por ejemplo: pending, processing, awaiting_confirmation, confirmed, retry_scheduled, manual_review, compensated y not_applicable. Cada transición debe tener un responsable y una condición comprobable. Una actualización condicional, como pasar a processing solo si el estado anterior es pending, reduce carreras entre consumidores.
Construir el proceso de reconciliación
La reconciliación puede ejecutarse mediante un comando PHP programado, un worker dedicado o un flujo operativo. Debe trabajar con ventanas temporales: no examine operaciones creadas hace segundos si la integración externa tarda normalmente varios minutos. Defina la ventana con datos reales de latencia y revísela al cambiar límites o proveedores.
Para cada operación elegible, compare fuentes de verdad previamente definidas. La base local puede ser autoridad sobre la intención y la versión del dato; el sistema externo, sobre si recibió o creó el recurso. Cuando no exista una consulta fiable al destino, la evidencia puede ser un acuse firmado, un identificador de proveedor o una comprobación diferida por archivo de resultado.
- Seleccione operaciones no confirmadas que superen su plazo esperado.
- Compruebe si el efecto existe usando
operation_id, clave idempotente o una clave de negocio inequívoca. - Compare campos relevantes y versiones, no únicamente la existencia del recurso.
- Clasifique el caso como ausente, correcto, divergente, ambiguo o no aplicable.
- Ejecute la acción autorizada y guarde la decisión con su evidencia.
Un resultado ambiguo no debe convertirse automáticamente en reencolado. Si una llamada pudo haber creado un recurso pero no hay forma de consultarlo de manera fiable, reintentar podría duplicar un cobro, una notificación o un documento. En esos casos, bloquee la acción automática y envíe el caso a un panel de excepciones con contexto suficiente para decidir.
Corregir sin introducir nuevos daños
La acción depende de la discrepancia y del coste de equivocarse. Reencolar es adecuado cuando el efecto falta y la operación es idempotente. Compensar puede revertir un efecto incorrecto mediante una operación de negocio explícita, no mediante un borrado técnico indiscriminado. Marcar para revisión es preferible ante ambigüedad, conflicto de versiones o consecuencias financieras. Cerrar como no aplicable sirve cuando la entidad fue cancelada o sustituida conforme a reglas documentadas.
Las reparaciones manuales también deben dejar rastro: quién tomó la decisión, qué evidencia consultó, qué acción aplicó y cuál fue el resultado. Limite permisos y evite botones que ejecuten una operación sin mostrar la entidad, la versión, el destino y el riesgo de duplicación.
Observabilidad y pruebas que validan el diseño
Los logs correlacionados por operation_id facilitan seguir una operación entre web, workers y servicios externos. Las métricas útiles no se limitan a excepciones: mida antigüedad de operaciones pendientes, cantidad en revisión manual, tasa de divergencias, reintentos por causa y tiempo hasta confirmación. Las alertas deben dispararse por acumulación, antigüedad o incumplimiento de plazo, no por cada error aislado.
Pruebe fallos representativos: caída después del efecto externo y antes de persistir la confirmación; ejecución duplicada; mensaje fuera de orden; reinicio del worker; timeout con resultado remoto incierto; indisponibilidad prolongada; y cambios de versión mientras una operación sigue pendiente. La prueba debe comprobar tanto el estado final como la ausencia de duplicados y la calidad de la evidencia almacenada.
Ejemplo: sincronizar un registro con un sistema externo
Suponga que una aplicación PHP sincroniza un registro de cliente. Al modificarlo, crea la operación sync_customer con un identificador estable y la versión local esperada. El worker envía esos valores al destino como clave idempotente. Si recibe confirmación válida, persiste el identificador remoto y cambia el estado a confirmed.
Si el timeout ocurre tras enviar la petición, el worker deja la operación en awaiting_confirmation. El reconciliador consulta el destino por la clave idempotente. Si encuentra la misma versión, confirma. Si no la encuentra, programa un nuevo envío. Si encuentra una versión diferente, marca el caso para revisión en vez de sobrescribir datos que podrían haber sido modificados legítimamente en el otro sistema.
Checklist para incorporar reconciliación sin reescribir el proceso

- Inventarie los trabajos existentes y priorice los que producen efectos externos, afectan dinero, datos regulatorios o procesos difíciles de repetir.
- Para cada tipo, documente el efecto esperado, la fuente de verdad y la evidencia que permitirá confirmarlo.
- Verifique en el broker y consumidores concretos qué ocurre ante caídas, reconocimientos tardíos, persistencia, redelivery y orden de mensajes.
- Añada un
operation_idestable y propáguelo en mensaje, logs, llamadas externas y registros de estado. - Introduzca una tabla de operaciones con estados, intentos, plazos, clave idempotente y evidencia; empiece en modo observación si es necesario.
- Defina transiciones condicionales y una política escrita para reintentar, confirmar, compensar, escalar o cerrar como no aplicable.
- Implemente un reconciliador limitado a una ventana temporal y a un tipo de operación piloto.
- Valide con casos de duplicado, timeout ambiguo, caída entre pasos, reordenamiento y reinicio antes de automatizar correcciones.
- Cree un panel o consulta de excepciones con antigüedad, entidad, evidencia y acción recomendada.
- Revise periódicamente métricas, operaciones estancadas y decisiones manuales para ajustar plazos, reglas y controles.
La adopción gradual permite mejorar la fiabilidad sin reemplazar toda la arquitectura: primero haga visibles las operaciones inciertas, después confirme resultados y, por último, automatice únicamente las correcciones cuya seguridad pueda demostrar.



