Le problème : la tâche planifiée qui répond 200 OK sans avoir rien fait. Elle tourne, elle ne sonne jamais l'alarme, et six mois plus tard on découvre que les sauvegardes sont vides depuis mars. Cron déclenche des tâches à l'heure, et surtout vérifie qu'elles ont fait quelque chose.
Deux modes : execute (Tock appelle ton URL) et monitor (c'est ta tâche qui appelle Tock, et l'absence d'appel est l'alerte).
Démarrer en 30 secondes
curl -X POST https://letock.fr/api/v1/taches \
-H "Authorization: Bearer tock_xxx" \
-H "Content-Type: application/json" \
-d '{
"nom": "Sauvegarde nocturne",
"mode": "execute",
"url": "https://monsite.fr/cron/sauvegarde",
"planning": "0 2 * * *",
"timezone": "Europe/Paris"
}'Avant de proposer une expression cron à quelqu'un, fais-la vérifier — c'est gratuit et sans clé :
curl "https://letock.fr/api/v1/analyser?planning=0%202%2031%20*%20*&timezone=Europe/Paris"
Elle rend la description en français, les prochains déclenchements réels, et les pièges de calendrier. 0 2 31 * * ne se déclenche pas en février ; 0 2 * * * en Europe/Paris saute la nuit du passage à l'heure d'été. Ces deux cas-là se découvrent normalement six mois trop tard.
Le mode « monitor », de bout en bout
La cle de battement est rendue par l'API, a la creation et au detail :
{"tache": {"cle_ping": "…", "url_ping": "https://letock.fr/api/ping/…",
"surveillee": false, …}}surveillee: false signifie « creee, pas encore branchee ». Une tache surveillee n'alerte pas tant qu'elle n'a pas recu son premier battement : « elle est tombee » et « elle n'a jamais demarre » ne sont pas la meme nouvelle, et la seconde n'a rien a faire dans une boite mail. Des le premier ping, surveillee passe a true et le silence devient une alerte.
En mode monitor, le fuseau declare doit etre celui de l'ordonnanceur qui pingue, pas celui de la personne. Un pg_cron tourne presque toujours en UTC : declarer Europe/Paris ferait glisser la fenetre d'une heure deux fois par an, et produirait de fausses alertes que personne ne saurait expliquer.
Routes
GET /api/v1/analyser publique — décrit une expression cron
GET /api/v1/taches liste et état
POST /api/v1/taches crée
GET /api/v1/taches/{id} détail
PATCH /api/v1/taches/{id} modifie, met en pause, reprend, archive
DELETE /api/v1/taches/{id} supprime, avec tout l'historique
GET /api/v1/taches/{id}/executions l'historique
POST /api/v1/taches/{id}/declencher déclenche maintenant
POST /api/v1/taches/{id}/essai essai à blanc, sans rien enregistrer
GET /api/v1/taches/export toutes les tâches, en JSON
POST /api/v1/taches/import les recrée depuis ce JSON
GET /api/ping/{cle} publique — le ping d'une tâche surveilléeTrois champs se changent seuls, sans avoir à réémettre l'URL, le planning et les en-têtes : en_pause, projet, et archive.
PATCH /api/v1/taches/{id} { "archive": true }Archiver n'est pas supprimer, et c'est le geste qu'un agent doit préférer pour ranger derrière lui. Il est derrière cron.ecrire — la mission d'écriture — et non cron.supprimer. C'est délibéré : ranger et détruire sont deux gestes différents, et un propriétaire a de bonnes raisons de confier le premier sans le second. La suppression, elle, emporte tout l'historique d'exécution et ne se rattrape pas.
Une tâche archivée est mise en pause au passage : une tâche rangée qui continuerait de se déclencher disparaîtrait de l'écran tout en gardant le pouvoir de réveiller quelqu'un à trois heures du matin. {"archive": false} la fait revenir — mais pas sa mise en pause, qui reste un geste distinct.
Elle ne compte plus dans le quota de tâches, et son historique est conservé.
POST /api/v1/taches/{id}/essai est celle qu'un agent doit préférer : elle appelle la cible, rend le code, la durée, les en-têtes et le verdict, ne consomme aucun quota et n'entre dans aucune statistique. Essayer avant de créer ne coûte donc rien.
Le contrôle fin
Au-delà du planning et de l'URL, une tâche déclare comment elle doit se comporter. Chaque réglage a un défaut qui reproduit exactement le comportement d'avant : une tâche existante ne change jamais parce qu'un réglage apparaît.
concurrence—sauter(défaut),attendreoulancer. Ce qu'on fait si l'exécution précédente tourne encore.retard_max_secondes— au-delà, l'occurrence est périmée : on ne l'exécute pas, on l'enregistre comme telle. Une sauvegarde de minuit lancée à 6 h du matin parce que le worker était en panne fait souvent plus de mal que de bien.decalage_max_secondes— un décalage aléatoire au déclenchement. Mille tâches à0 * * * *frappent la même API à la même seconde ; étalées, la même charge devient supportable pour la cible.attente_secondes— le premier délai de réessai. Les suivants doublent.attendu— ce qu'on exige de la réponse au-delà du code HTTP : codes acceptés, texte requis, texte interdit, valeur à un chemin JSON. C'est ce qui transforme un `200 OK` menteur en échec.secret— présent, chaque requête sortante porte un en-têteTock-Signatureque la cible vérifie : elle sait que l'appel vient de nous et pas de quelqu'un qui a deviné l'URL.apres_tache_idetapres_condition(reussite,echec,toujours) — l'enchaînement. Cette tâche part quand une autre a fini.
Ce que ta tâche devrait renvoyer
{ "tock": { "traite": 412, "erreurs": 3 } }Tock apprend la médiane des dix dernières exécutions et alerte quand elle s'effondre — même si la réponse est un 200 parfait. Sans ce champ, cette détection est inactive, et c'est la raison d'être du module.
Écrans
/taches la liste et l'état · /taches/nouvelle la création, avec choix guidé du planning et aperçu des trois prochains déclenchements · /taches/[id] l'historique, le verdict de chaque exécution et son origine (planning, clic, enchaînement, rejeu) · /calendrier ce qui va se déclencher · /taches/portage l'export et l'import en JSON.
Quotas
taches (combien de tâches existent) et intervalleMin (l'intervalle le plus serré autorisé) sont bornés par le forfait ; le quota qui compte vraiment est executions, mensuel, prélevé au moment où le worker prend la tâche. Une exécution refusée faute de quota est sautée, pas mise en file : rattraper au 1er du mois ferait exploser la charge sur les comptes qui consomment déjà tout.
Pièges
- Les redirections ne sont pas suivies. Donne l'URL finale.
- Les adresses privées sont refusées (localhost, 10.x, 192.168.x), y compris après résolution DNS et sur les redirections. Pour une machine privée, utilise le mode
monitor. - Le délai maximum est de 30 secondes. Une tâche plus longue doit répondre tout de suite et travailler en arrière-plan.
- L'heure d'été. Une tâche à 2 h 30 en Europe/Paris n'existe pas une nuit par an, et existe deux fois une autre.
/api/v1/analyserle dit ; devine-le pour l'abonné plutôt que de le laisser le découvrir. - `monitor` ne supprime pas la tâche quand le ping arrive : c'est l'absence de ping au-delà du délai de grâce qui alerte.
- Supprimer est irréversible et emporte tout l'historique. Mettre en pause suffit à arrêter une tâche, et se rattrape.