Tracing: root spans for background jobs, retire raw OTel spans (#142)

Background work has no request parent, so each job now opens a named
tracing root and carries it into its fan-out:

- watcher: `watcher.tick` (scan=quick|full) entered per tick on the
  watcher's std thread, `watcher.library` per library, and
  `watcher.playlist_cleanup` per orphaned-HLS pass. face_watch /
  clip_watch carry the ambient span into every per-candidate
  tokio::spawn and give each call its own `face_watch.detect` /
  `clip_watch.encode` span.
- thumbnails: `creating thumbnails` via #[instrument]; per-video spans on
  rayon workers name their parent explicitly.
- video actors: `playlistgenerator.generate_playlist` and
  `preview_clip.generate` are tracing roots that instrument their futures.
- reels: `reel.job` (created before the spawn, so on-demand jobs stay in
  the request trace), `reel.pregen_batch`, `reel.cache_sweep`.
- RefreshThumbnailsMessage and the dead-code GIF job move to tracing.

No raw OpenTelemetry span creation is left outside otel.rs;
`global_tracer` is removed.

tests/otel_background.rs pins the std-thread tick -> block_on -> spawn
shape and the rayon explicit-parent shape.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Cameron CordesandClaude Opus 5.5 committed 2026-09-29 17:02:40 -04:00
1 parent b6deca2a52
commit 26115b3378
11 files changed
+330 -179

No files matched your search

+16
View File
@@ -125,6 +125,7 @@ pub fn cleanup_orphaned_playlists(
}
info!("Running orphaned HLS cleanup");
let _pass = tracing::info_span!("watcher.playlist_cleanup").entered();
let start = std::time::Instant::now();
// Snapshot every live content_hash currently in image_exif.
@@ -418,6 +419,15 @@ pub fn watch_files(
let is_full_scan = since_last_full.as_secs() >= full_interval_secs;
// Root span per tick: this loop runs on a plain std thread, so a
// synchronous `entered()` guard is the right shape. Everything the
// tick does (probes, drains, ingest, maintenance) nests under it.
let _tick = tracing::info_span!(
"watcher.tick",
scan = if is_full_scan { "full" } else { "quick" },
)
.entered();
// Fresh snapshot per tick — picks up PATCH /libraries/{id}
// mutations to `enabled` / `excluded_dirs` without restart.
let libs: Vec<libraries::Library> =
@@ -436,6 +446,12 @@ pub fn watch_files(
);
continue;
}
let _lib_span = tracing::info_span!(
"watcher.library",
library = %lib.name,
library_id = lib.id,
)
.entered();
// Availability probe: every tick checks that the
// library's mount is reachable, is a directory, is