Saltar al contenido
Development

Dos triggers, un id de KV: por qué los builds de preview estaban a oscuras en imperfectsystems.com

Por Victor Da Luz
cloudflareciastrodev-logsite

Los builds de ramas que no son de producción en este sitio estuvieron a oscuras desde principios de julio. Se hace push a una rama de features y no vuelve nada de Cloudflare, sin URL de preview, sin check en el PR, nada. La base de conocimiento del repo tenía una nota al respecto: npx wrangler versions upload estaba auto-aprovisionando un namespace de KV para algo llamado SESSION y chocando con el de producción. Arreglarlo necesitaba “un id/preview_id real” fijado en wrangler.toml. Ese era el plan de entrada. No era toda la historia.

¿De dónde sale siquiera un binding de SESSION?

Primera sorpresa: nada en este código usa sesiones de Astro. Ningún Astro.session en ningún lado. Entonces, ¿por qué un build necesitaba siquiera un namespace de KV llamado SESSION?

Resultó que @astrojs/cloudflare habilita sesiones respaldadas por KV por defecto, se usen o no, a menos que se configure explícitamente un driver distinto. Lo registra directamente en la salida del build, si se presta atención:

[@astrojs/cloudflare] Enabling sessions with Cloudflare KV with the "SESSION" KV binding.

Eso inyecta una entrada kv_namespaces sin id en la config generada del build. Sin id, Cloudflare intenta auto-aprovisionar uno en cada deploy. Como el sitio nunca toca sesiones, la solución fue simple una vez que la encontré: crear un namespace real y fijar su id en wrangler.toml, igual que ya hace el binding existente GAME_FILES. Nada lee ni escribe nunca en él, solo necesita existir para que el adaptador deje de improvisar.

Había asumido que también iba a necesitar un preview_id para un segundo namespace, solo de preview, eso era lo que decía la nota original. Revisar la documentación de Cloudflare y correr wrangler versions upload --dry-run localmente mostró que eso no aplica acá: preview_id es un concepto de wrangler dev --remote, y el camino de preview de Workers Builds nunca lo lee. Un solo id fijado cubre tanto producción como preview.

El arreglo de KV no era todo el bug

Reconstruí localmente, confirmé que la config generada ahora mostraba un id real, y estaba listo para darlo por terminado. Antes de mergear, le pregunté directamente a Cloudflare cómo era en realidad el trigger de build de este repo, y encontré exactamente un trigger, limitado a branch_includes: ["main"]. Ningún build se dispara para nada que no sea main, esto nunca fue un caso de builds corriendo y fallando.

Había estado asumiendo que existía un solo trigger que manejaba tanto los builds de producción como los de preview, cambiando de comando según la rama. El modelo de Cloudflare es distinto: como máximo dos triggers por Worker, uno para la rama de producción, y opcionalmente uno completamente separado para todo lo demás. El checkbox “Builds for non-production branches” del dashboard maneja ese segundo trigger; no hay ningún campo en el primero que amplíe su alcance.

Mi primer instinto fue hacer PATCH al branch_includes del trigger existente para ponerlo en ["*"]. La compuerta de permisos de mi propia herramienta bloqueó el intento, la API pedía el objeto completo del trigger en ese PATCH, lo que significaba reenviar deploy_command, que seguía siendo el comando literal de producción wrangler deploy, ahora pegado a un trigger que coincidiría con cualquier rama. Y ese no es un riesgo hipotético: una nota anterior de la base de conocimiento de este mismo proyecto documentaba que disparar manualmente un build contra una rama de feature a través del trigger de producción despliega esa rama directo a producción, sin confirmación, sin dry run. Buen recordatorio de que “simplemente ampliar el filtro” puede convertirse en silencio en “desplegar cada push a producción.”

El arreglo real fue un segundo trigger: el mismo comando de build, branch_excludes: ["main"], y un comando de deploy que no puede llegar a producción, npx wrangler versions upload en vez de wrangler deploy. versions upload crea una nueva versión del Worker y se detiene ahí; nada se promueve a tráfico en vivo.

Viéndolo funcionar de verdad

No quería confiar solo en la teoría. Hice push de la rama con el arreglo después de crear el segundo trigger y saqué los logs del build directamente de la API de Cloudflare:

Executing user deploy command: npx wrangler versions upload --config wrangler.toml dist/server/entry.mjs
...
env.SESSION (c49871…)   KV Namespace
Worker Version ID: cd654a24-…

Build de preview real, comando correcto, SESSION vinculado al id fijado sin error de aprovisionamiento. Y un check-run Workers Builds: imperfectsystems-com apareció contra el commit, completed/success, que es exactamente la señal que faltaba antes. Ese vacío específico (sin check previo al merge en los PRs abiertos) ya me había quemado una vez: un PR agrupado de dependabot escondió un salto de versión mayor de Tailwind porque no había nada que fallara en el PR antes del merge. Ahora sí debería tener una oportunidad real de detectar eso la próxima vez.

Conclusiones

El comportamiento por defecto “útil” de un adaptador de framework (acá, el soporte de sesiones) puede inyectar requisitos de infraestructura que nadie pidió, vale la pena leer lo que registra la herramienta de build, no solo lo que produce. “Preview” es una palabra sobrecargada: preview_id en wrangler.toml tiene que ver con wrangler dev, no con los deploys de preview de Workers Builds de Cloudflare, sistemas distintos, misma palabra. Cuando una verificación de permisos bloquea una acción, eso no es fricción para esquivar; esta en particular atrapó un plan que habría vuelto a pegar en silencio un comando de deploy de producción a un filtro de rama comodín. Y no confío en un cambio de configuración de CI/CD hasta haber visto correr un build real a través de él y leído los logs, los dry-runs locales acertaron la forma, pero solo el build en vivo probó el arreglo.

Lecturas relacionadas