Docs/ Operaciones/ Tareas cron

Tareas cron

Ejecute un comando o una solicitud HTTP según una programación. Lea «Dónde se ejecuta el comando» antes de su primera tarea: una tarea programada no se ejecuta dentro del contenedor en marcha de su aplicación, sino en uno desechable que recibe las mismas variables.

Crear una tarea cron

Las tareas programadas se gestionan desde la página Tareas programadas del panel, o con sh0 cron. Una tarea suele estar vinculada a una aplicación.

  1. Abre Tareas programadas en la barra lateral y haz clic en Crear tarea programada.
  2. Nombre -- una etiqueta, por ejemplo nightly-report.
  3. Aplicación -- la aplicación a la que pertenece la tarea. Sin aplicación, solo se aceptan comandos HTTP (ver más abajo).
  4. Programación -- una expresión cron de 5 campos, evaluada en UTC.
  5. Comando -- una petición HTTP (curl, wget o una URL sola), o un programa que se ejecuta en un contenedor.
  6. Opcional: una Imagen del contenedor (vacía = la imagen de la aplicación) y un Tiempo de espera (segundos), 300 por defecto. Después, crea la tarea.

Lo mismo desde la CLI, en un servidor donde se ejecutaron estos comandos:

Terminal
$ sh0 cron create --app my-api --name nightly-report \
    --schedule "0 3 * * *" \
    --command "curl -s -X POST https://api.example.com/internal/report"
Cron job 'nightly-report' created (id: 72173a56-1962-47dc-88e5-2a276ef3bfcc)

$ sh0 cron trigger 72173a56-1962-47dc-88e5-2a276ef3bfcc
Cron job 'nightly-report' triggered.

$ sh0 cron runs 72173a56-1962-47dc-88e5-2a276ef3bfcc
RUN ID                                STATUS      EXIT    DURATION    STARTED
----------------------------------------------------------------------------------------------------
9e329bc7-01c5-41ec-9eb5-5ab745fde533  success     0       295ms       2026-10-02 02:33:23

Dónde se ejecuta el comando

sh0 elige el modo de ejecución según el comando y la configuración de la tarea, en este orden:

  • Solicitud HTTP -- un comando que empieza por curl o wget, o una URL sola, no lo ejecuta un shell: sh0 envía la solicitud él mismo, desde el servidor, con un límite de 30 segundos. Se respetan -X, -H y -d. Un estado de respuesta de 400 o más marca la ejecución como fallida. Para una tarea vinculada a una aplicación, un nombre interno de su proyecto (my-api.internal, o my-api a secas) se resuelve hacia ese servicio.
  • Imagen de la aplicación -- cualquier otro comando se ejecuta en un contenedor nuevo y desechable iniciado desde la imagen actual de la aplicación, con un usuario no root, en la red de sh0 y en la red de su proyecto. No es su contenedor en marcha: los archivos que la aplicación escribe en ejecución no están ahí, y el contenedor se elimina después de la ejecución.
  • Imagen explícita -- si Imagen del contenedor está definida, el contenedor desechable parte de esa imagen.
  • Sin aplicación ni imagen -- un comando que no es HTTP se rechaza en el momento de ejecutarse. sh0 nunca ejecuta un comando programado en el host.
Note
Desde 1.10.3: El contenedor recibe las variables de su aplicación. Una tarea vinculada a una aplicación recibe sus variables de ejecución y las de su proyecto, prevaleciendo el valor de la aplicación, exactamente como los contenedores de la aplicación. Las variables de compilación no se transmiten. La salida de una tarea se conserva en su historial: un comando que imprime un secreto lo deja ahí, legible por cualquiera con acceso de desarrollador a la aplicación.

Medido en una aplicación Node.js con GREETING en la aplicación y REGION en su proyecto: la tarea env muestra ambas, junto a las variables incluidas en la imagen.

env -- app image (Node.js 22)
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=0.0.0.0
REGION=eu431
GREETING=hello431
NODE_VERSION=22.23.3
YARN_VERSION=1.22.22
PORT=3000
HOME=/home/node

GREETING y REGION aparecen. La línea HOME=/home/node muestra el usuario no root.

Reglas del comando

Un comando es un único programa con sus argumentos. sh0 lo comprueba al crear la tarea:

  • Sin shell. Se rechazan los caracteres ; | & > < y el acento grave, $( y los saltos de línea. No hay tuberías, ni cadenas &&, ni expansión de variables.
  • Las comillas solo cuentan en las peticiones HTTP. En un contenedor, el comando se divide por espacios: sh -c "echo hi" no hace lo que haría un shell. En las peticiones HTTP las comillas se respetan, así que -H "Authorization: Bearer …" funciona.
  • Las redirecciones se eliminan en lugar de rechazarse: > /dev/null, 2>/dev/null, &> /dev/null y 2>&1 se quitan antes de la comprobación, de modo que una línea copiada de un crontab se acepta.
  • 4096 caracteres como máximo.
Terminal
$ sh0 cron create --app my-api --name cleanup --schedule "0 3 * * *" --command "env | grep X"
Error: Invalid command: Command contains forbidden character '|'. Use simple commands without shell operators. (VALIDATION_ERROR)

Tareas que necesitan la base de datos o secretos

Una tarea vinculada a una aplicación ve sus variables y resuelve los nombres internos de su proyecto, así que un comando como python manage.py cleanup lee la misma DATABASE_URL y alcanza el mismo db.internal. Cuando el trabajo pertenece a su aplicación en marcha, quedan otras dos opciones:

  • Un endpoint HTTP. Exponga la tarea como una ruta de su aplicación, protegida por un token, y deje que la tarea programada la llame por su nombre interno. El trabajo se ejecuta dentro de su aplicación en marcha, con su conexión a la base de datos y sus secretos.
  • O prográmala dentro de la aplicación, con el planificador de tu framework (por ejemplo Celery beat, node-cron o el planificador de Laravel), cuando la tarea no deba ser accesible por HTTP en absoluto.
Command
curl -s -X POST -H "Authorization: Bearer <token>" http://my-api.internal:3000/internal/cleanup
Note
sh0 envía la solicitud desde el servidor y resuelve my-api.internal (o my-api) solo entre los servicios en marcha del proyecto de la tarea. Un nombre que no corresponde a ningún servicio en marcha falla con un mensaje explícito; una aplicación sin proyecto, o que se ejecuta en un nodo remoto, debe llamarse por su URL pública. El token figura en claro en el comando de la tarea, visible para cualquiera que pueda leer la tarea: no le dé ningún otro uso.

Sintaxis de expresiones cron

sh0 usa expresiones cron estándar de 5 campos. Cada campo representa una unidad de tiempo:

Cron expression format
┌───────────── minute (0-59)
│ ┌───────────── hour (0-23)
│ │ ┌───────────── day of month (1-31)
│ │ │ ┌───────────── month (1-12)
│ │ │ │ ┌───────────── day of week (0-6, Sunday = 0)
│ │ │ │ │
* * * * *
SímboloSignificadoEjemplo
*Cada valor* * * * * = cada minuto
,Lista de valores0 8,12,18 * * * = 8am, mediodía, 6pm
-Rango0 9-17 * * * = cada hora de 9am a 5pm
/Paso*/15 * * * * = cada 15 minutos

Patrones comunes

Frequently used cron schedules
# Every minute
* * * * *

# Every 5 minutes
*/5 * * * *

# Every hour at minute 0
0 * * * *

# Every day at midnight
0 0 * * *

# Every day at 3:30 AM
30 3 * * *

# Every Monday at 9:00 AM
0 9 * * 1

# First day of every month at midnight
0 0 1 * *

# Every weekday (Mon-Fri) at 6:00 AM
0 6 * * 1-5
Note
Las programaciones se evalúan en UTC, sea cual sea la zona horaria del servidor. 0 3 * * * se ejecuta a las 03:00 UTC. El planificador busca tareas pendientes cada 60 segundos, así que una ejecución puede empezar hasta un minuto después de su hora.

Historial de ejecuciones y registros

Cada ejecución se registra con su estado (success, failed o timeout), código de salida, duración, horas de inicio y fin, y salida. En el panel, abre Historial de ejecución en una tarea y muestra la salida de una ejecución. Desde la CLI: sh0 cron runs <id>.

Note
sh0 conserva las últimas 100 ejecuciones de cada tarea y elimina las más antiguas. La salida estándar y la de error se conservan cada una hasta 64 KB.

Habilitar y deshabilitar tareas

  • Deshabilitar detiene las ejecuciones programadas sin borrar la tarea ni su historial; Habilitar las reanuda.
  • Ejecutar ahora (o sh0 cron trigger <id>) lanza una ejecución de inmediato, sea cual sea la programación.
  • Eliminar una tarea (sh0 cron delete <id>) elimina también su historial.

Tiempos de espera, solapamiento y límites

  • Tiempo de espera -- 300 segundos por defecto (--timeout en la CLI). Una ejecución que lo supera se registra con el estado timeout y el mensaje «Job timed out after Ns».
  • Solapamiento -- mientras una ejecución de una tarea sigue en curso, el planificador no lanza otra. La ocurrencia omitida no queda registrada en el historial.
  • 50 tareas por aplicación.
  • Sin reintentos ni notificaciones de fallo. Una ejecución fallida no se reintenta y no envía ninguna alerta: revisa el historial, o haz que el endpoint al que llama la tarea informe de sus propios fallos.