← Blogue

Comment lancer une tâche cron sans serveur

Railyard

4 août 2026 · 7 min de lecture

Suivez ça sur votre propre serveur. Commencer gratuitement, sans carte

La tâche elle-même est petite : sauvegarder une table, envoyer un résumé hebdomadaire, faire expirer quelques lignes. Monter tout un serveur, ou toute une application, pour lancer une seule commande selon un horaire semble disproportionné par rapport à la tâche, et c’est un instinct raisonnable. Ce guide couvre ce qu’il vous faut vraiment pour un script qui doit tourner sur un horaire plutôt que répondre à des requêtes : d’abord la version manuelle simple (une petite VM, crontab, et la partie que les gens sautent, confirmer que ça a vraiment tourné), puis le vrai Cron de Railyard, décrit avec précision plutôt qu’avec des espoirs.

Ce qu’il vous faut

  • Le script lui-même, exécutable comme une seule commande (node send-digest.js, python cleanup.py, une ligne shell), avec les variables d’environnement dont il a besoin déjà identifiées.
  • Pour la version manuelle : un accès SSH à une petite VM Linux. Un Hetzner CX23 (2 vCPU, 4 Go de RAM, 5,99 € HT/mois) suffit largement pour un script qui tourne quelques secondes ou minutes selon un horaire, pas en continu.

La version manuelle : une VM, crontab, et la preuve que ça a tourné

Écrire la tâche comme une seule commande

Enveloppez tout ce qui dépasse une ligne dans un script, pour que cron n’ait qu’une seule chose à appeler :

#!/usr/bin/env bash
set -euo pipefail

cd /opt/myjob
set -a
source /opt/myjob/.env
set +a

node send-digest.js >> /var/log/myjob/digest.log 2>&1

set -euo pipefail compte particulièrement ici parce que cron ne relance pas une exécution échouée pour vous ; sans ça, une étape qui échoue en cours de route peut laisser le reste du script tourner quand même et signaler un succès. set -a avant source exporte chaque variable que le fichier .env définit, pour que la commande de la dernière ligne les hérite vraiment ; cron lui-même démarre les tâches avec un environnement presque vide, pas celui de votre shell.

Rendez-le exécutable et lancez-le une fois à la main avant de le planifier :

chmod +x /opt/myjob/run.sh
/opt/myjob/run.sh
echo $?

Vous devriez voir 0.

Ajouter l’entrée crontab, avec verrouillage

crontab -e
0 3 * * * /usr/bin/flock -n /tmp/myjob.lock /opt/myjob/run.sh

flock -n prend un verrou exclusif avant de lancer la commande et abandonne immédiatement, plutôt que de mettre en file une deuxième exécution, si l’exécution précédente détient encore le verrou. Sans ça, une tâche qui dure parfois plus longtemps chevauche sa propre prochaine exécution planifiée, souvent contre les mêmes lignes.

Confirmer que ça a vraiment tourné, pas juste que c’était planifié

Qu’une entrée crontab existe ne dit rien sur le succès ou non de l’exécution de la nuit dernière. La version honnête de la « surveillance » ici est un interrupteur homme-mort : la tâche elle-même signale son succès en appelant une URL, et quelque chose vous alerte si ce signal n’arrive pas à l’heure prévue. Héberger soi-même cette vérification est en soi un petit service toujours actif ; voir héberger Uptime Kuma soi-même ou héberger Healthchecks soi-même pour cette partie spécifiquement. L’entrée crontab devient :

0 3 * * * /usr/bin/flock -n /tmp/myjob.lock /opt/myjob/run.sh && curl -fsS https://hc-ping.com/your-check-id

Le && signifie que le signal ne se déclenche que si run.sh s’est terminé avec succès ; un échec silencieux apparaît maintenant comme un signal manquant plutôt que comme rien du tout.

Pour le détail sur les fuseaux horaires et la journalisation complète que cette version condensée saute, remplacer Heroku Scheduler par cron couvre le même terrain plus en profondeur, notamment pourquoi le comportement par défaut UTC-contre-heure-locale de cron système piège presque tout le monde en quittant une plateforme avec son propre planificateur.

Ce qu’est vraiment le Cron de Railyard

Railyard a une vraie fonctionnalité de tâche planifiée, appelée Cron dans le tableau de bord, et ça vaut la peine de la décrire précisément plutôt que vaguement. Ajoutez une entrée avec un nom, un horaire, et une commande :

  • L’horaire est une simple expression cron à cinq champs (0 3 * * *), analysée et évaluée de la même façon que cron système en lit une, en UTC.
  • La commande s’exécute dans une nouvelle instance de l’image de votre application elle-même, exactement le même build que vos processus web et worker font déjà tourner, pas un conteneur séparé que vous devez garder synchronisé à la main.
  • Chaque exécution est enregistrée : heure de début, code de sortie, et sortie, conservées comme historique par tâche, pour que « est-ce que la tâche de la nuit dernière a vraiment tourné » soit une page que vous consultez plutôt qu’un fichier de log dont vous devez vous souvenir de l’existence.

Ce dernier point remplace la solution de contournement par interrupteur homme-mort de la version manuelle ci-dessus par quelque chose d’intégré : l’historique d’exécution lui-même est le registre de si la tâche a tourné et de ce qui s’est passé, sans qu’un deuxième service ne fasse un ping à un troisième pour vous le dire.

Une limite honnête, la même que vous rencontreriez en la faisant tourner vous-même : le Cron de Railyard ne saute pas une exécution pendant qu’une précédente de la même tâche est encore en cours. La protection flock -n de la version manuelle est quelque chose que vous devez quand même intégrer à la tâche elle-même si elle peut réalistement dépasser son propre intervalle, soit en rendant la commande sûre à exécuter deux fois en même temps, soit en lui faisant vérifier et s’arrêter tôt si elle détecte qu’une exécution précédente est encore en cours.

Voir Workers et tâches planifiées pour comment Cron se place à côté de l’onglet Workers séparé, qui gère les processus d’arrière-plan de longue durée (un consommateur de file d’attente, par exemple) plutôt que les tâches planifiées ; les deux font tourner la même image, donc un déploiement qui corrige l’application corrige en même temps ses tâches planifiées, par construction.

Mise en place

Ajoutez la tâche depuis l’onglet Cron de l’application : un nom, l’expression d’horaire, et la commande, exactement comme vous la taperiez si vous vous connectiez en SSH dans le conteneur de l’application pour la lancer directement. Les variables d’environnement dont la tâche a besoin sont les mêmes que celles déjà définies sous l’onglet Variables de l’application, puisque la commande s’exécute dans cette même image et ce même environnement ; il n’y a pas de fichier .env séparé à sourcer et pas de crontab à éditer sur un serveur, parce qu’il n’y a pas de serveur séparé qui fait tourner la tâche du tout. Voir variables et secrets.

Dépannage

La tâche tourne au mauvais moment. Le Cron de Railyard évalue les horaires en UTC ; si vous avez écrit un horaire en supposant l’heure locale, convertissez-le en UTC plutôt que de supposer que la plateforme le lit autrement. C’est la même conversion qui piège les gens en quittant un planificateur de plateforme qui utilisait aussi UTC, comme celui de Heroku.

La tâche semble se chevaucher avec elle-même. Comme noté plus haut, ce n’est pas empêché automatiquement ; ajoutez la même protection que vous ajouteriez à une entrée crontab ordinaire, soit l’idempotence dans la commande elle-même, soit une vérification explicite de verrou au début du script, si la tâche peut réalistement dépasser son propre intervalle.

Rien ne confirme que la tâche a tourné. Vérifiez d’abord l’historique d’exécution directement dans l’onglet Cron plutôt que les logs de l’application ; une exécution terminée avec un code de sortie non nul apparaît quand même là, avec son code de sortie et sa sortie, ce qui est généralement plus rapide à lire que de reconstituer la même information depuis l’onglet Logs.

FAQ

Ai-je besoin d’une application entière juste pour lancer un script planifié ? Pas plus que vous auriez besoin d’un serveur entier pour la version manuelle. Si le script est vraiment tout ce que vous déployez, sans aucun processus web, c’est une forme normale et prise en charge ; une tâche planifiée et une application uniquement-worker signifient juste qu’il n’y a pas de type de processus web, pas qu’il manque quelque chose.

Quel est l’intervalle minimum qu’un horaire peut utiliser ? La syntaxe cron standard à cinq champs descend jusqu’à une fois par minute (* * * * *), le même plancher que cron système ; rien en dessous de la minute n’est exprimable dans ce format, peu importe où c’est évalué.

En quoi est-ce différent d’un worker en arrière-plan ? Un worker est un processus qui démarre une fois et continue de tourner indéfiniment, consommant une file d’attente ou gardant une connexion ouverte. Une tâche cron démarre, fait une chose, et se termine, selon un horaire. Ce sont des formes de processus différentes pour des tâches différentes, couvertes par deux fonctionnalités séparées et liées plutôt que par une seule qui essaierait de faire les deux.

Que se passe-t-il si le serveur sous-jacent redémarre en plein milieu d’une tâche ? La même chose qui arrive à n’importe quel processus tué d’une autre façon : il s’arrête, inachevé. Une tâche sûre à exécuter deux fois (idempotente) tolère ça sans traitement particulier ; une qui ne l’est pas doit être rendue idempotente peu importe ce qui la planifie, puisque le même mode d’échec existe aussi sous un cron simple sur une VM.

Puis-je déclencher la tâche manuellement, pas seulement selon son horaire ? Oui, une tâche planifiée peut être lancée à la demande depuis le même endroit où vous consultez son historique d’exécution, indépendamment d’attendre sa prochaine heure planifiée, ce qui est utile pour tester un changement avant de lui faire confiance pour le vrai créneau de 3 h du matin.

Que ce soit une ligne de crontab sur une VM à cinq dollars ou une entrée dans un tableau de bord, une tâche cron reste les trois mêmes choses en dessous : une commande, un horaire, et un moyen de savoir qu’elle a vraiment tourné. Bien faire le troisième point, c’est généralement ce qui manquait, pas les deux premiers.

Pourquoi les gens choisissent Railyard pour ça

  • Votre propre compte infonuagique. Déployez sur DigitalOcean, Hetzner, Vultr, AWS, OVHcloud, ou n'importe quel serveur Linux par SSH, facturé directement par votre fournisseur, sans majoration.
  • Un prix fixe par équipe. L'offre gratuite est gratuite pour toujours : un serveur plus un serveur de base de données, trois applications, sans carte. Pro coûte 19 $ par mois pour jusqu'à cinq serveurs et un nombre illimité d'applications. Team coûte 49 $ par mois avec des serveurs illimités. Aucuns frais par application, par déploiement, par siège ou par gigaoctet.
  • Des gabarits en un clic. Déployez des applications open source, comme des bases de données, des outils d'analyse et des outils de développement, sur votre propre serveur en un clic.
  • Des bases de données gérées. Postgres, MySQL et Redis, avec des sauvegardes planifiées, vérifiées par restauration, et la récupération à un point dans le temps.
  • Déploiement par push. Déployez depuis GitHub, GitLab ou la CLI, avec HTTPS automatique et des mises en production sans interruption.

Planifiez-la depuis la page de l'application

Le Cron de Railyard exécute une commande dans l'image de votre application selon un horaire, avec un historique pour chaque exécution, sans crontab ni VM dédiée.

Offre gratuite, sans carte, et 14 jours de Pro pour chaque nouvelle équipe. Prix fixe par équipe.