Lo que está duplicado a propósito
Hay dos ficheros que existen por duplicado en notification-api y notification-worker, y no
es un descuido. Si vas a tocar alguno, esta es la página.
src/core/queue-contract.ts
Es el formato de lo que viaja por Redis: los nombres de las colas y las interfaces EmailData y
PushData. Hoy es byte a byte idéntico en los dos repos, y su propia cabecera dice quién manda:
notification-apies la fuente de la verdad — este fichero debe permanecer idéntico ennotification-worker, empujado allí conpnpm queue-contract:push-to-worker.
Ese script es literalmente un cp:
cp src/core/queue-contract.ts ../notification-worker/src/core/queue-contract.ts
Y se vuelve a copiar en cada build de Docker, el mismo mecanismo que usa prisma/schema.prisma.
Qué pasa si divergen: el CI del worker lo detecta. Antes de desplegar hace diff de los dos
ficheros contra main de notification-api y falla si no son idénticos. Sin ese paso no se vería
nada al compilar: los dos repos siguen compilando por separado,
porque cada uno tiene su copia y su copia es coherente consigo misma. Lo que falla es en ejecución,
con trabajos ya encolados: el productor mete un campo que el consumidor no lee, o el consumidor
espera uno que nunca llega. No hay tipo que te proteja de esto: te protege el diff del CI.
prisma/schema.prisma
Misma historia y misma dirección: manda notification-api, se empuja al worker. Los dos servicios
hablan con la misma base de datos, así que dos schemas distintos significa dos clientes Prisma
que discrepan sobre las mismas tablas.
Ojo con una asimetría: core/constants.ts no es parte de lo sincronizado. Se parece mucho entre
repos pero difiere a propósito —las rutas de import de los enums de Prisma no coinciden, y el worker
no reexporta JOBS porque no lo usa—. No lo copies de un lado al otro.
Por qué no es un paquete compartido
Es lo primero que apetece hacer, y sería peor. Un paquete npm compartido entre dos repos que se
despliegan por separado te obliga a publicar y versionar para cambiar un campo, y a resolver
en qué orden despliegas. Con el cp pagas una copia manual; con el paquete pagas una release
entera cada vez.
Es un tradeoff deliberado, no deuda pendiente.
Cómo cambiar el contrato sin romper producción
El orden importa, y el motivo es que hay trabajos en vuelo:
- Cambia
queue-contract.tsennotification-api. - Empújalo al worker y ajusta el consumidor.
- Publica primero la api. El CI del worker compara sus copias con
mainde la api, así que si el worker va antes su CI falla y no despliega. El deploy de la api reconstruye además el worker con elmainque tenga en ese momento. - Después el worker, con el consumidor ya ajustado.
Entre los pasos 3 y 4 la api nueva convive con el consumidor anterior, así que el cambio tiene que ser compatible hacia atrás: un campo nuevo que el worker aún no lee no rompe nada. Si no lo es, los trabajos en cola con el formato nuevo fallan sus tres intentos.
Si el cambio es incompatible en los dos sentidos —renombrar un campo, no añadirlo— haz dos pasos:
añade el nuevo, despliega ambos, y quita el viejo en un despliegue posterior, cuando ya no queden
trabajos antiguos en la cola. Es la misma cautela que documenta el RENAME COLUMN pendiente de
providerId.