El teléfono sonó a las 2 a.m. Un supervisor de turno de un DC de comercio electrónico en Riverside prácticamente gritaba: "Lao Mi, ¡el sorter se volvió loco! ¡El mismo cartón acaba de ser escaneado tres veces, los chutes están desbordados, la banda está a punto de atorarse!"

Le dije que mantuviera las manos fuera del equipo y que, en cambio, sacara dos archivos de registro. Media hora después llamó de vuelta, con voz avergonzada: "Tenías razón... el WES liberó la misma ola dos veces."

He visto esta película demasiadas veces. En el piso siempre dicen "el sistema está fallando". En mi experiencia, nueve de cada diez veces, lo que parece una falla es el WES y el WCS peleando entre ellos — y la causa raíz casi siempre es la interfaz entre ambos. Aquí está la cadena de diagnóstico que realmente uso, del síntoma a la causa raíz.

No toques la línea. Haz que los dos registros hablen primero.

Los conflictos de comandos suelen morir de una de dos formas: despacho duplicado de tareas, o una confirmación de estado perdida. El WES envía un comando de liberación, la red se entrecorta, el acuse de recibo nunca regresa, así que el WES dispara el mismo comando de nuevo tras su timeout configurado. El WCS acepta ambos con gusto — porque nadie construyó deduplicación por número de tarea en la interfaz. Una tarea entra dos veces a la cola de clasificación, y el mismo paquete es solicitado por el chute dos o tres veces.

El paso uno es siempre el mismo: saca el registro de despacho del WES y el registro de recepción de comandos del WCS lado a lado, y alinea los números de tarea uno por uno. Pero aquí hay una trampa que atrapa a ocho de cada diez almacenes: los relojes de los dos servidores no están sincronizados. El registro del WES dice que el comando salió a las 02:14:03; el del WCS dice que fue recibido a las 02:13:47. Cuando los timestamps no coinciden, nunca puedes establecer causa y efecto. Antes de tocar ningún registro, confirma que ambos lados estén en NTP — y confirma la zona horaria. He visto más de un sitio donde un lado registraba en UTC y el otro en hora local.

Me tropecé con esto yo mismo en 2021 en un DC en Ontario, de más de cien mil pies cuadrados, con un sorter de banda cruzada. Temporada pico, en plena noche: el mismo paquete apareció en el sistema tres veces. Con ambos registros sobre la mesa, era evidente — el WES había liberado la ola dos veces, separadas exactamente por un intervalo de timeout, y el registro de ejecución del WCS mostraba dos números de tarea idénticos, ambos honrados. Causa raíz en una frase: reenvío por timeout contra una interfaz sin idempotencia.

Hay un compromiso genuino escondido en ese valor de timeout. Si lo pones demasiado corto, cada jitter de red dispara un reenvío falso; si lo pones demasiado largo, los cambios de ola y los pedidos urgentes se quedan esperando. Ese número no puede ser una suposición — tiene que salir de la latencia medida en tu red real, y el número de reintentos y la política de backoff pertenecen por escrito en la especificación de la interfaz. Demasiados integradores lo dejan como un acuerdo verbal, y el acuerdo se va por la puerta con el ingeniero.

Línea de clasificación en el piso de ejecución

Cuando un pedido urgente desplaza una tarea en curso, ¿adónde va la tarea vieja?

La apropiación por pedido urgente es la zona de conflicto más fea, y la lógica es más complicada que la simple duplicación. El WES recibe un pedido urgente, marca parte de las tareas de la ola actual como canceladas, e inserta las nuevas tareas. Pero el WCS ya empujó esos comandos al PLC — la cancelación llega demasiado tarde para detener un desvío ya en movimiento. Ahora el mismo paquete está siendo llamado al chute A por la tarea vieja y al chute B por la nueva. ¿A cuál obedece el equipo?

El diagnóstico significa seguir dos hilos: la máquina de estados de tareas del WES (¿la cancelación realmente salió, y exactamente cuándo?) y la cola de comandos del WCS (¿en qué punto de la ejecución estaba ese comando cuando llegó la cancelación?). La evidencia decisiva sigue siendo el delta de timestamps — cuándo se emitió la cancelación versus cuándo terminó realmente la ejecución del comando. Haz la aritmética y sabrás si la cancelación tenía alguna chance de alcanzarlo.

Hay una trampa más sutil debajo: los dos lados ni siquiera hablan los mismos números de tarea. El WES usa sus propios IDs de tarea; el WCS los traduce a números de comando de equipo, con una tabla de mapeo en medio. Pierde esa tabla y los dos sistemas hablan sin entenderse. Lo vi en 2023 en un almacén a las afueras de Chicago — la tabla de mapeo vivía en memoria, el servicio WCS se reinició durante la noche, y se perdió. El ingeniero del turno nocturno miró los dos registros y no pudo encontrar ni una sola tarea coincidente. No porque no hubiera registros, sino porque los números no cuadraban. La solución es poco glamorosa pero efectiva: persiste la tabla de mapeo en disco, y haz que el registro del WCS lleve el número de tarea original del WES de principio a fin.

Y aquí va mi veredicto sobre los pedidos urgentes: no hagas apropiación dura a menos que tu volumen lo exija. Dale a los pedidos urgentes su propio chute o su propia ola — no toques las tareas que ya están en ejecución. Los pocos minutos que ahorras al apropiar no cubren el costo de un atoro de línea. Si debes apropiar, la cancelación tiene que ser en dos fases: una pre-cancelación que bloquee los comandos no ejecutados en el WCS, luego una cancelación formal; todo lo que ya está en movimiento pasa por un flujo de compensación posterior a la ejecución. Esperar que un solo comando de cancelación le gane a la física es simplemente faltarle el respeto a la velocidad de la luz.

Deja de preguntar por qué. Hazlo idempotente.

Ambos modos de falla comparten una causa raíz: la interfaz no es idempotente. Lo que se necesita del lado del WES es simple — cada tarea lleva un número de tarea globalmente único, y los reenvíos conservan el mismo número. Del lado del WCS: al recibir, verificar "¿ya vi este número de tarea?"; si sí, responder éxito y no ejecutar de nuevo. Las confirmaciones de estado funcionan igual — adjunta un número de secuencia monótonamente creciente para que el WES pueda ordenar por sí solo las confirmaciones fuera de orden o duplicadas.

En la aceptación, le entrego al integrador tres frases, y van al contrato como anexo: primera, corta la red unos segundos y reconecta — ninguna tarea puede ejecutarse dos veces. Segunda, reinicia el WCS — los mapeos históricos de tareas deben sobrevivir. Tercera, cancelar un pedido urgente contra una tarea en ejecución debe disparar una acción de compensación definida, no solo "la cancelación fue enviada". Si pasan esas tres, el noventa por ciento de las historias de fantasmas de la capa de ejecución nunca ocurren.

Mi veredicto se mantiene: nueve de cada diez "fallas del sistema" son interfaces sin idempotencia. Del décimo restante, la mitad son relojes no sincronizados y la otra mitad es la mano temblorosa de alguien sobre un botón a las 2 a.m.

Antes de tu próxima puesta en marcha, desconecta el cable de red unos segundos y vuelve a conectarlo tú mismo. Solo un sistema que sobreviva esos pocos segundos merece tu temporada pico.

Traducido del inglés. En caso de discrepancia, prevalece la versión en inglés.