Skip to content

Jobs & files

Récupère les fichiers media publiés dont la row DB a disparu (média hard-deleté hors-bande, upload avorté ayant écrit le WebP avant la row, purge SQL manuelle…). Scanne le root publié (MEDIA_STORAGE_PATH), ne retient que les WebP primaires <hex>.webp, batch les ids et interroge la DB : un fichier sans row est un orphelin. Le supprimer retire aussi son compagnon -blurhash.webp.

Sécurité — dry-run par défaut. Rien n’est supprimé sans ?delete=1. Un dry-run rapporte exactement ce qu’une vraie passe supprimerait.

Le scan est plafonné (?limit, défaut 1000, max 50000 fichiers examinés par appel) pour rester borné sur un arbre à plusieurs millions de fichiers. Quand capped = true, la borne a été atteinte — relancer pour continuer (en mode delete, l’ensemble des orphelins rétrécit au fil des suppressions).

Les originaux (root séparé, extension source) ne sont pas touchés : leur extension n’est pas déductible de l’id seul, et ce sont des archives froides — hors périmètre du nettoyage du root publié.

Query params

  • limit (int, optionnel) : 1..50000 fichiers à examiner. Défaut 1000.
  • delete (bool, optionnel) : 1 / true pour réellement supprimer. Défaut off (dry-run).

Réponse (200)

{
"status": "ok",
"dryRun": true,
"scanned": 1000,
"orphansFound": 7,
"deleted": 0,
"capped": true,
"sample": ["01a3471992e44c60a8f08321f713635a", "..."],
"durationMs": 142
}
ChampSens
dryRuntrue tant que ?delete=1 n’est pas passé
scannednombre de WebP primaires examinés
orphansFoundfichiers sans row DB
deletedfichiers réellement supprimés (0 en dry-run)
cappedtrue si la borne limit a été atteinte (il peut rester des orphelins)
sampleaperçu des ids orphelins (max 100)

Erreurs

StatusBodySens
400{ "error": "Invalid limit." }limit non entier ou hors 1..50000
403{ "error": "..." }auth KO

Exemple curl

Terminal window
# Dry-run (audit)
curl -s -X POST -H "Authorization: Bearer $ADMIN_API_TOKEN" \
"http://hydrogen.dev.com/admin/jobs/cleanup-orphan-files?limit=5000"
# Suppression effective
curl -s -X POST -H "Authorization: Bearer $ADMIN_API_TOKEN" \
"http://hydrogen.dev.com/admin/jobs/cleanup-orphan-files?limit=5000&delete=1"

Force un drain immédiat d’un tampon habituellement vidé par cron, sans accès shell (Postman / Talend). L’endpoint n’est qu’un déclencheur HTTP : il appelle exactement le même FlushService::flush() que les entry-points bin/*-flush.php (aucune logique dupliquée).

{job} (la route restreint déjà aux valeurs valides) :

jobService(s)Équivaut au cron
countersmedia + user (les deux en un appel)bin/media-counters-flush.php + bin/user-counters-flush.php
notificationsdigest OneSignalbin/notifications-flush.php
trackingtampon de clics d’affiliationbin/tracking-flush.php

Idempotent par nature : un flush sur un tampon vide renvoie des compteurs à zéro. Un échec de transaction laisse remonter l’exception → 500 JSON plat (l’opérateur relance), comme un cron qui sortirait en code 2.

Réponse (200)

{
"job": "counters",
"summary": {
"media": { "drained": 0, "bumped": 0, "deletedEvents": 0, "gcRows": 0 },
"user": { "drained": 0, "bumped": 0, "deletedEvents": 0, "gcRows": 0 }
}
}
{ "job": "notifications", "summary": { "recipients": 3, "pushed": 3, "skipped": 0, "failed": 0 } }
{ "job": "tracking", "summary": { "drained": 42, "bumped": 12, "deletedEvents": 42 } }

Erreurs

StatusBodySens
400{ "error": "Unknown job '…'. Expected: counters, notifications, tracking." }garde défensive (la regex de route 404 avant, en principe)
403{ "error": "..." }auth KO
500{ "error": "..." }échec de flush (transaction) — relancer

Exemples curl

Terminal window
curl -s -X POST -H "Authorization: Bearer $ADMIN_API_TOKEN" \
"http://hydrogen.dev.com/admin/jobs/flush/counters"
curl -s -X POST -H "Authorization: Bearer $ADMIN_API_TOKEN" \
"http://hydrogen.dev.com/admin/jobs/flush/tracking"

Observabilité de la file IA work.media_to_describe (FIFO des médias en attente de description, consommée par un worker hors-bande). Jusqu’ici l’admin était aveugle sur ce backlog. Lecture seule, un seul round-trip vers la base work.

Réponse (200)

{
"size": 42,
"oldestEnqueuedAt": "2026-06-19T08:12:00+00:00",
"oldestAgeSeconds": 1834,
"enqueuedLastHour": 7,
"enqueuedLast24h": 120
}
ChampSens
sizeprofondeur de la file (médias en attente)
oldestEnqueuedAttimestamp de la tête de file (null si vide)
oldestAgeSecondsâge de la tête en secondes — grandit ⇒ le worker décroche
enqueuedLastHour / enqueuedLast24htaux d’arrivée récent, à comparer au débit du worker
Terminal window
curl -s -H "Authorization: Bearer $ADMIN_API_TOKEN" \
"http://hydrogen.dev.com/admin/jobs/describe-queue"

Réinjecte un média bloqué dans la file IA (worker mort en plein processing, ligne de queue perdue, retry après failed). INSERT IGNORE idempotent + remise de media.status à pending (sauf s’il l’est déjà) pour que le cycle de vie reste cohérent et qu’un futur claim soit légal.

Refuse un média en état terminal (published / rejected) : il a déjà un verdict, le redécrire serait une régression (409).

Body

ChampTypeRequisSens
mediaIdstring (32 hex)ouiid du média à réinjecter

Réponse (200)

{
"status": "ok",
"mediaId": "d26d1600cde54bd095e09f8b68ace05f",
"previousStatus": "failed",
"mediaStatus": "pending",
"alreadyQueued": false
}
ChampSens
previousStatusétat du média avant requeue
mediaStatustoujours pending après requeue
alreadyQueuedtrue si la ligne était déjà dans la file (réinjection no-op)

Erreurs

StatusBodySens
400{ "error": "Body must be JSON object with 'mediaId' 32-hex string." }corps absent / mediaId manquant ou mal formé
404{ "error": "Media not found." }id inconnu
409{ "error": "Cannot requeue a media in terminal state '<state>'." }média published / rejected
403{ "error": "..." }auth KO
Terminal window
curl -s -X POST -H "Authorization: Bearer $ADMIN_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "mediaId": "d26d1600cde54bd095e09f8b68ace05f" }' \
"http://hydrogen.dev.com/admin/jobs/describe-queue/requeue"