macOS BuildCaptain fija tus pipelines de Jenkins en la barra de menús de macOS — estado, logs y controles de build a un clic.

Deja de hacer polling: migra Jenkins de pollSCM a webhooks

pollSCM pregunta a tu servidor Git "¿hay algo nuevo?" con un temporizador. Los webhooks dejan que el servidor Git responda en el instante en que lo hay. Aquí tienes cómo migrar, y cuándo el polling sigue siendo la opción correcta.

Loris Siegenthaler Escrito por Loris Siegenthaler · Creador de BuildCaptain
10 min de lectura
Actualizado el 7 de agosto de 2026

Casi todas las instancias de Jenkins empiezan igual. Alguien crea un job, marca Poll SCM, escribe * * * * * porque quiere que las builds sean rápidas y sigue con lo suyo. Dos años después hay cuatrocientos jobs haciendo lo mismo, el log de acceso del servidor Git es 95% Jenkins y las builds siguen tardando hasta un minuto en arrancar.

El polling no está mal. Es solo el plan B, y la mayoría de los equipos lo ejecuta como opción por defecto. Aquí verás qué hace en realidad, cuánto cuesta y cómo pasar a webhooks los jobs que no lo necesitan.

Qué hace pollSCM en realidad

El trigger pollSCM programa una comprobación periódica contra el repositorio configurado en el job. En cada ejecución, Jenkins pregunta al SCM si la revisión que construyó por última vez sigue siendo la punta de la rama. Si no lo es, se encola una build. Si lo es, no pasa nada y el sondeo queda registrado en el Git Polling Log del job.

En una pipeline declarativa se ve así:

pipeline {
    agent any
    triggers {
        pollSCM('H/5 * * * *')
    }
    stages {
        stage('Build') {
            steps {
                sh './gradlew build'
            }
        }
    }
}
Un bloque triggers en un Jenkinsfile solo surte efecto cuando Jenkins ha leído ese archivo al menos una vez — lo que significa ejecutar el job a mano la primera vez. El trigger es configuración que vive en el repo, y Jenkins no puede conocerla hasta haber hecho checkout del repo.

Existen dos variantes de polling, y no cuestan lo mismo. El plugin de Git normalmente puede responder "¿se ha movido la punta?" con un único git ls-remote contra el remoto — sin workspace, sin clone, sin agente. Pero si la configuración de SCM del job necesita un workspace para decidir (ciertas configuraciones de changelog/exclusión de rutas, algunos otros plugins de SCM), Jenkins tiene que ocupar un ejecutor y tocar un checkout real en cada sondeo. Esa es la variante que sale cara.

La sintaxis cron, y por qué la H importa

Jenkins usa cinco campos — minuto, hora, día del mes, mes, día de la semana — y añade un carácter que el cron normal no tiene: H.

H significa "hash". Jenkins convierte el nombre del job en un valor estable dentro del rango permitido, de modo que cada job recibe su propio desplazamiento y se queda ahí. Es la diferencia entre cuatrocientos jobs sondeando todos en el segundo 00 de cada minuto y cuatrocientos jobs repartidos uniformemente por todo el intervalo.

# Every five minutes, at a per-job offset inside each five-minute window
H/5 * * * *

# Once an hour, at a per-job minute
H * * * *

# Once a night, some time between 02:00 and 04:59
H H(2-4) * * *

# Twice a day, on weekdays only
H H(8-9),H(16-17) * * 1-5

Nunca escribas * * * * *. Significa "cada minuto", apila todos los jobs en el mismo tick y la página de configuración del job te avisará al respecto. Si de verdad necesitas tiempos de reacción de un minuto, esa es la señal más clara posible de que quieres un webhook, no un polling más rápido.

La misma sintaxis gobierna el trigger cron (construir según un horario, haya cambios o no) y el intervalo de Scan Repository Triggers de los proyectos multibranch, así que merece la pena aprenderla una sola vez.

Lo que el polling te cuesta

Tres facturas distintas, y los equipos normalmente solo notan la tercera.

Carga en el servidor SCM. Un job sondeando cada cinco minutos son 288 peticiones al día. Cuatrocientos jobs son 115.000 peticiones diarias contra tu servidor Git, prácticamente todas respondiendo "no, nada ha cambiado". Las instancias autoalojadas de GitLab o Bitbucket lo sienten directamente. Los proveedores en la nube tienen límites de peticiones que el polling autenticado va consumiendo, y así es como los equipos descubren que su Jenkins es la razón de que su cuota de API se haya agotado antes de la hora de comer.

Carga en el controlador. El polling se ejecuta en el controlador de Jenkins, en un pool de hilos acotado. Cuando los sondeos empiezan a tardar más de lo esperado — un remoto lento, un repositorio que necesita workspace, un tropiezo de red — el pool se atasca y Jenkins te avisa de que se está quedando sin hilos de polling. En ese punto los sondeos van con retraso, así que las builds van con retraso — y la ventaja que el polling debía darte es justo la que has perdido.

Latencia, siempre. Con un intervalo de cinco minutos, la espera media entre un push y el arranque de una build es de dos minutos y medio, y el peor caso es de cinco. Ese retraso es invisible en un dashboard y extremadamente visible para el desarrollador que acaba de subir un fix y está ahí sentado viendo cómo no pasa nada. La propia documentación del plugin de Git no se anda con rodeos: para minimizar el retraso entre un push y una build, configura el repositorio remoto para que notifique a Jenkins con un webhook.

Webhooks con GitHub

El plugin de GitHub expone un único endpoint en tu Jenkins para todos los repositorios:

https://jenkins.example.com/github-webhook/

La barra final no es opcional. En el repositorio de GitHub, ve a Settings → Webhooks → Add webhook y configura:

  • Payload URL — la URL de arriba.
  • Content typeapplication/json. El plugin también acepta application/x-www-form-urlencoded, pero JSON es la elección convencional y la que usan todos los ejemplos.
  • Secret — un secreto compartido, si has configurado uno en el lado de Jenkins. Configúralo; un trigger de builds sin autenticar es una puerta abierta.
  • Events — "Just the push event" para un job normal; añade pull requests para multibranch.

En el job de Jenkins, marca GitHub hook trigger for GITScm polling. El nombre describe exactamente lo que ocurre: el hook no construye a ciegas, le dice a Jenkins que sondee ahora mismo. Jenkins confirma el cambio contra el repositorio y entonces construye. Conservas la fiabilidad del polling y te deshaces de su calendario.

En una pipeline declarativa:

pipeline {
    agent any
    triggers {
        githubPush()
    }
    stages { /* … */ }
}

Para las pipelines multibranch y las organization folders, el plugin GitHub Branch Source usa el mismo endpoint /github-webhook/, pero el efecto es distinto: un evento de push dispara un escaneo de la rama afectada en lugar de una build de un job fijo. Eso es lo que hace que las ramas nuevas y los pull requests nuevos aparezcan en Jenkins en segundos en lugar de en el siguiente escaneo periódico. Configura el webhook una sola vez a nivel de organización en GitHub y todos sus repositorios quedan cubiertos.

Mantén habilitado el intervalo de Scan Repository Triggers de multibranch como red de seguridad, pero ponlo largo — una vez al día es de sobra. Recoge los eventos que se perdieron mientras Jenkins se reiniciaba, sin volver al polling como mecanismo principal.

Webhooks con GitLab

El plugin de GitLab funciona por proyecto en lugar de a través de un endpoint global único. Cada job recibe su propia URL:

https://jenkins.example.com/project/<job-name>

Los jobs dentro de carpetas incluyen la ruta de la carpeta — /project/platform/api-service. La página de configuración del job muestra la URL exacta junto a la casilla Build when a change is pushed to GitLab, junto con un botón Generate para el token secreto. Copia ambos en Settings → Webhooks del proyecto de GitLab: la URL en el campo URL, el token en Secret token. Los proyectos multibranch usan la misma forma de URL.

No caigas en la tentación de apuntar el webhook de GitLab a /job/<name>/build. El propio README del plugin es explícito en que eso lo puentea por completo — pierdes los datos de rama y de merge request del payload, y con ellos todos los filtros que dependen de esos datos.

pipeline {
    agent any
    triggers {
        gitlab(
            triggerOnPush: true,
            triggerOnMergeRequest: true,
            branchFilterType: 'All'
        )
    }
    stages { /* … */ }
}

Si usas algo que no es ni GitHub ni GitLab — Gitea, un mirror autoalojado, una herramienta interna que sube tags — el plugin Generic Webhook Trigger te da un endpoint protegido por token en /generic-webhook-trigger/invoke?token=… y te permite vincular valores del payload JSON a parámetros de build. Para proyectos multibranch, el plugin Multibranch Scan Webhook Trigger hace lo mismo con los escaneos en /multibranch-webhook-trigger/invoke?token=… — y acepta el token como cabecera en lugar de como parámetro de query, lo que lo mantiene fuera de los logs de acceso.

Cuándo el polling sigue siendo la respuesta correcta

Los webhooks requieren algo que no todos los Jenkins tienen: una ruta desde el servidor SCM hasta Jenkins. Sigue con el polling cuando

  • Jenkins está detrás de un cortafuegos corporativo o en una red privada sin camino de entrada desde tu servidor Git, y no quieres abrirle un agujero al cortafuegos solo para eso;
  • no administras el repositorio y no puedes añadirle webhooks;
  • la fuente directamente no es un sistema con capacidad de webhooks — el servidor SVN de un proveedor, un mirror de artefactos, una carpeta en un sistema de archivos.

En esos casos, haz polling de forma deliberada y no por accidente: H/5 * * * * para algo genuinamente interactivo, H/30 * * * * o H * * * * para todo lo demás, y polling ligero estilo ls-remote allí donde el plugin de SCM lo soporte. El polling como plan B meditado y con un intervalo sensato es buena ingeniería. El polling cada minuto en cuatrocientos jobs porque nadie revisó el valor por defecto, no.

Un híbrido también es legítimo, y a menudo es justo donde conviene acabar: webhooks como vía rápida, más un sondeo lento — diario, o cada pocas horas — como respaldo que recoge los eventos perdidos por un reinicio de Jenkins o un fallo de entrega del webhook.

Quiet period: el ajuste que frena las tormentas de builds

Cuando los triggers se disparan al instante, las ráfagas se hacen visibles. Un desarrollador sube tres commits en veinte segundos, o un script hace push a cinco ramas a la vez, y Jenkins encola una build por cada uno.

El quiet period es la respuesta integrada. Cuando se dispara una build, Jenkins la retiene en la cola durante unos segundos; los triggers adicionales del mismo job que llegan durante esa ventana se funden con la build pendiente en lugar de encolarse detrás de ella. El valor global por defecto es de cinco segundos (Manage Jenkins → System), y cualquier job puede sobrescribirlo en Advanced — o en una pipeline con options { quietPeriod(30) }.

Conviene saber dos cosas. La ventana no se extiende con triggers posteriores: una build que lleva cuatro segundos esperando arranca igualmente un segundo después, lleguen los pushes que lleguen entre tanto. Y cinco segundos es un valor por defecto razonable para el polling, pero a menudo demasiado corto una vez estás en webhooks. Si tu equipo hace push en ráfagas, entre 30 y 60 segundos en los jobs caros convierte cinco builds redundantes en una, y el único coste es medio minuto de latencia que nadie iba a notar.

Los triggers rápidos merecen feedback rápido

Esto es lo que cambia tras la migración. Con polling, el intervalo entre hacer push y enterarte estaba dominado por el trigger — hacías push, ibas a por un café, volvías y mirabas Jenkins. Con webhooks la build arranca en segundos, y la parte más lenta del ciclo ahora eres : la pestaña del navegador que tienes que acordarte de mirar, el dashboard que refrescas, el canal de Slack donde la notificación llega entre otras doscientas.

Que es justo el problema para el que construimos nuestra propia herramienta — lo que sigue es, abiertamente, publicidad de la casa. BuildCaptain es nuestra app — un cliente nativo de la barra de menús de macOS para Jenkins. Fija las pipelines que te importan y su estado queda en la barra de menús; cuando una se pone en rojo recibes una notificación nativa, y un clic abre el grafo de etapas, el log del step que falla y un botón de relanzar. Acabas de conseguir que Jenkins reaccione a tus pushes al instante; esto se encarga de que tú te enteres igual de rápido.