feat(job-registry): remplace /api/admin/internal/trigger-*

remplace /api/admin/internal/trigger-* to /api/admin/jobs/{...}/trigger
remove OXICLOUD_ENABLE_ADMIN_INTERNAL_ENDPOINTS
This commit is contained in:
Edouard Vanbelle
2026-07-27 23:40:40 +02:00
parent dfedde54a4
commit f66f7fa31f
24 changed files with 155 additions and 464 deletions
+5 -8
View File
@@ -117,11 +117,7 @@ async fn run(registry: Arc<JobRegistry>) {
/// `args` is passed through to `JobHandler::run`. The supervisor's
/// periodic ticks pass `JobRunArgs::default()`; the admin trigger
/// endpoint forwards parsed query params such as `?force=true`.
pub(super) async fn dispatch(
name: &str,
entry: Arc<JobEntry>,
args: &JobRunArgs,
) -> JobOutcome {
pub(super) async fn dispatch(name: &str, entry: Arc<JobEntry>, args: &JobRunArgs) -> JobOutcome {
// Try to acquire the single-permit gate. `try_acquire` is
// non-blocking — if held, we know the previous run is still
// executing and skip this tick.
@@ -372,9 +368,10 @@ mod tests {
// Kick off dispatch 1 in the background — it holds the permit
// for ~200 ms.
let entry_bg = entry.clone();
let bg = tokio::spawn(async move {
dispatch("overrun", entry_bg, &JobRunArgs::default()).await
});
let bg =
tokio::spawn(
async move { dispatch("overrun", entry_bg, &JobRunArgs::default()).await },
);
// Give dispatch 1 time to grab the permit.
tokio::time::sleep(Duration::from_millis(50)).await;
+2 -10
View File
@@ -216,11 +216,7 @@ impl JobRegistry {
/// `args` is forwarded to `JobHandler::run`. Admin trigger routes
/// use `JobRunArgs { force: query.force }`; programmatic callers
/// that just want a plain run pass `JobRunArgs::default()`.
pub async fn trigger(
self: &Arc<Self>,
name: &str,
args: &JobRunArgs,
) -> Option<JobOutcome> {
pub async fn trigger(self: &Arc<Self>, name: &str, args: &JobRunArgs) -> Option<JobOutcome> {
let entry = self.get(name).await?;
Some(super::engine::dispatch(name, entry, args).await)
}
@@ -367,10 +363,6 @@ mod tests {
#[tokio::test]
async fn trigger_returns_none_for_unknown_job() {
let reg = Arc::new(JobRegistry::new());
assert!(
reg.trigger("nope", &JobRunArgs::default())
.await
.is_none()
);
assert!(reg.trigger("nope", &JobRunArgs::default()).await.is_none());
}
}
+6 -6
View File
@@ -2471,15 +2471,15 @@ impl DedupService {
.await
}
/// Test-only variant that bypasses the orphan grace window — used by
/// `POST /api/admin/internal/trigger-gc?force=true` so the
/// Test-only variant that bypasses the orphan grace window — used
/// by `POST /api/admin/jobs/dedup_gc/trigger?force=true` (via the
/// `JobRunArgs.force` dispatch in `JobHandler::run`) so the
/// integration suite can reap just-orphaned blobs synchronously
/// (waiting out the production 1 h grace inside a test run is a
/// non-starter). Drops the same rows the regular sweep would, just
/// without the time floor. Unsafe under concurrent uploads because
/// it reopens the TOCTOU window the grace closes — only the
/// admin-internal route, itself gated by
/// `OXICLOUD_ENABLE_ADMIN_INTERNAL_ENDPOINTS`, may reach here.
/// admin-triggered `?force=true` path reaches here.
pub async fn garbage_collect_force(&self) -> Result<(u64, u64), DomainError> {
self.garbage_collect_with_grace(0).await
}
@@ -3150,8 +3150,8 @@ impl crate::infrastructure::scheduler::JobHandler for DedupService {
/// cleanup already reaped everything.
///
/// `args.force = true` skips the orphan grace window
/// (`garbage_collect_force` — grace_secs = 0), matching the legacy
/// `POST /admin/internal/trigger-gc?force=true` semantics. Unsafe
/// (`garbage_collect_force` — grace_secs = 0). Same semantic as
/// `POST /api/admin/jobs/dedup_gc/trigger?force=true`. Unsafe
/// under concurrent uploads: only reachable through the admin
/// endpoint and only intentionally used by tests + operator
/// diagnostic sessions.
@@ -118,9 +118,9 @@ impl JobHandler for GrantCleanupService {
/// listings can see it without a second lookup.
///
/// `args.force = true` collapses the grace window to zero for
/// this run only — matches the legacy
/// `POST /admin/internal/trigger-grant-cleanup?force=true` shape.
/// The configured `self.grace_days` is not mutated.
/// this run only — same semantic as
/// `POST /api/admin/jobs/grant_cleanup/trigger?force=true`. The
/// configured `self.grace_days` is not mutated.
async fn run(&self, args: &JobRunArgs) -> JobOutcome {
let grace_override = if args.force { Some(0) } else { None };
let effective_grace = grace_override.unwrap_or(self.grace_days);