refactor(transcode): thread fs ops + atomic cache publish

- run blocking Path.exists/read_text off the event loop via anyio.to_thread
- publish HLS renditions by building into a temp dir then atomic rename, so a
  reader never sees a playlist referencing half-written segments
- per-writer temp name for opus so two concurrent jobs can't interleave
- drop a track's cached renditions on delete so they don't dangle

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Цвылев Александр Вадимович
2026-07-29 10:53:35 +03:00
parent d16c6085c9
commit 9a78cf5261
5 changed files with 46 additions and 6 deletions
+2 -1
View File
@@ -10,6 +10,7 @@ import re
import uuid
from typing import Annotated
import anyio
from fastapi import APIRouter, Header, Query, Response
from fastapi.responses import FileResponse, StreamingResponse
@@ -78,7 +79,7 @@ async def stream_hls_playlist(
await enqueue_transcode_quiet(track_id, hls=True)
raise NotFoundError("HLS rendition is being prepared; retry shortly.")
body = path.read_text()
body = await anyio.to_thread.run_sync(path.read_text)
if token:
body = _SEGMENT_LINE_RE.sub(rf"\1?token={token}", body)
return Response(body, media_type=_HLS_PLAYLIST_TYPE)
+7 -1
View File
@@ -3,6 +3,7 @@
import uuid
from typing import Annotated
import anyio
from fastapi import APIRouter, Query, Response
from fastapi.responses import StreamingResponse
@@ -33,7 +34,8 @@ from app.api.schemas.track import (
TrackUpdate,
)
from app.api.schemas.transcode import OptimizeEnqueuedOut
from app.application.transcode_service import bitrate_for_quality
from app.application.transcode_service import bitrate_for_quality, remove_track_cache
from app.core.config import get_settings
from app.domain.entities.album import Album
from app.domain.entities.track import Artist, Track
from app.domain.errors import NotFoundError, ValidationError
@@ -219,6 +221,10 @@ async def delete_track(
await track_repo.delete(track_id)
if track.storage_uri is not None:
await storage.delete(track.storage_uri)
# Drop any cached transcode renditions (Opus + HLS) so they don't dangle.
await anyio.to_thread.run_sync(
remove_track_cache, get_settings().transcode_cache_path, track_id
)
return Response(status_code=204)