Publications en échec : nouvel essai espacé au lieu de chaque minute

Une publication en échec gardait published_at à NULL et était renvoyée
à chaque passage du planificateur, soit toutes les minutes, sans fin.
Chaque essai multipliait les appels à l'API Graph, jusqu'à épuiser le
quota de l'application (code 4) puis déclencher le blocage anti-spam
de Meta (code 368).

- scheduled_posts : colonnes attempts et next_attempt_at ;
- délai croissant entre les essais (5 min → 3 h), plus long après une
  limite de débit (30 min → 4 h), abandon après 5 tentatives ;
- après une limite de débit, les autres publications de la même
  plateforme sont reportées au lieu d'aggraver le blocage ;
- reprogrammer une publication remet le compteur à zéro ;
- l'historique indique la prochaine tentative ou l'abandon.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018jcWbATGHxatn4V7qS3mr3
This commit is contained in:
Claude committed 2026-10-12 18:45:10 +00:00
1 parent 7f21e23a91
commit def7d8a2cb
9 files changed
+211 -9

No files matched your search

+2
View File
@@ -214,6 +214,8 @@ mod tests {
error: error.map(str::to_string),
publish_id: None,
publish_status: None,
attempts: 0,
next_attempt_at: None,
},
post: ScheduledPostPost {
id: "p".into(),
+6 -1
View File
@@ -160,7 +160,12 @@ async fn update_scheduled(
let mut patch = Patch::new();
if let Some(value) = body.get("scheduledAt").filter(|v| is_truthy(Some(v))) {
let date = js_date(value).ok_or_else(|| AppError::internal(FAILED))?;
patch = patch.set("scheduled_at", date);
// Reprogrammer relance les publications en échec ou abandonnées
patch = patch
.set("scheduled_at", date)
.set("attempts", 0)
.set("next_attempt_at", None::<Ts>)
.set_null("error");
state
.db
.update_post(&scheduled.post_id, Patch::new().set("scheduled_for", date))
+8 -1
View File
@@ -869,7 +869,14 @@ async fn update_post_inner(state: &AppState, id: &str, body: &Value) -> Outcome
if sp.published_at.is_none() {
state
.db
.update_scheduled_post(&sp.id, Patch::new().set("scheduled_at", new_date))
.update_scheduled_post(
&sp.id,
Patch::new()
.set("scheduled_at", new_date)
.set("attempts", 0)
.set("next_attempt_at", None::<Ts>)
.set_null("error"),
)
.await?;
}
}