plex deadlock + version showing stale + "disco" screen after docker update fixes

This commit is contained in:
Harvey
2026-04-18 23:03:13 +01:00
parent 10c593b254
commit 4f4591fb96
5 changed files with 73 additions and 4 deletions
+1 -1
View File
@@ -40,7 +40,7 @@ class PreferencesService:
self._settings = settings self._settings = settings
self._config_path = settings.config_file_path self._config_path = settings.config_file_path
self._config_cache: Optional[dict] = None self._config_cache: Optional[dict] = None
self._cache_lock = threading.Lock() self._cache_lock = threading.RLock()
self._migrate_musicbrainz_settings() self._migrate_musicbrainz_settings()
self._ensure_instance_id() self._ensure_instance_id()
+5 -2
View File
@@ -4,6 +4,9 @@ from fastapi.responses import FileResponse
from fastapi.staticfiles import StaticFiles from fastapi.staticfiles import StaticFiles
_NO_CACHE_HEADERS = {"Cache-Control": "no-cache"}
def mount_frontend(app: FastAPI): def mount_frontend(app: FastAPI):
backend_static = Path(__file__).parent / "static" backend_static = Path(__file__).parent / "static"
frontend_root = Path(__file__).resolve().parents[1] / "frontend" frontend_root = Path(__file__).resolve().parents[1] / "frontend"
@@ -83,7 +86,7 @@ def mount_frontend(app: FastAPI):
@app.get("/") @app.get("/")
async def serve_root(): async def serve_root():
if index_html.exists(): if index_html.exists():
return FileResponse(index_html) return FileResponse(index_html, headers=_NO_CACHE_HEADERS)
raise HTTPException(status_code=404, detail="Frontend not built yet") raise HTTPException(status_code=404, detail="Frontend not built yet")
@app.get("/{full_path:path}") @app.get("/{full_path:path}")
@@ -91,5 +94,5 @@ def mount_frontend(app: FastAPI):
if full_path.startswith("api"): if full_path.startswith("api"):
raise HTTPException(status_code=404, detail="API route not found") raise HTTPException(status_code=404, detail="API route not found")
if index_html.exists(): if index_html.exists():
return FileResponse(index_html) return FileResponse(index_html, headers=_NO_CACHE_HEADERS)
raise HTTPException(status_code=404, detail="Frontend not built yet") raise HTTPException(status_code=404, detail="Frontend not built yet")
+37
View File
@@ -77,6 +77,43 @@ class TestCreatePlexPin:
assert resp.status_code == 500 assert resp.status_code == 500
class TestGetOrCreateSettingNoDeadlock:
def test_get_or_create_setting_does_not_deadlock(self, tmp_path):
import threading
from core.config import Settings
from services.preferences_service import PreferencesService
config_path = tmp_path / "config.json"
settings = Settings(
root_app_dir=tmp_path,
config_file_path=config_path,
cache_dir=tmp_path / "cache",
library_db_path=tmp_path / "cache" / "library.db",
queue_db_path=tmp_path / "cache" / "queue.db",
)
result = None
exc = None
def run():
nonlocal result, exc
try:
prefs = PreferencesService(settings)
result = prefs.get_or_create_setting("plex_client_id", lambda: "test-client-id")
result = (result, prefs.get_or_create_setting("plex_client_id", lambda: "other"))
except Exception as e:
exc = e
t = threading.Thread(target=run)
t.start()
t.join(timeout=5)
assert not t.is_alive(), "Deadlock detected: PreferencesService hung for 5s"
assert exc is None
assert result[0] == "test-client-id"
assert result[1] == "test-client-id"
class TestPollPlexPin: class TestPollPlexPin:
def test_poll_pending(self, auth_client): def test_poll_pending(self, auth_client):
resp = auth_client.get("/plex/auth/poll?pin_id=12345") resp = auth_client.get("/plex/auth/poll?pin_id=12345")
@@ -30,7 +30,8 @@ export const getVersionQuery = () =>
staleTime: CACHE_TTL.VERSION_INFO, staleTime: CACHE_TTL.VERSION_INFO,
queryKey: VersionQueryKeyFactory.info(), queryKey: VersionQueryKeyFactory.info(),
queryFn: ({ signal }) => api.global.get<VersionInfo>(API.version.info(), { signal }), queryFn: ({ signal }) => api.global.get<VersionInfo>(API.version.info(), { signal }),
refetchOnWindowFocus: false refetchOnWindowFocus: false,
refetchOnMount: 'always'
})); }));
export const getUpdateCheckQuery = () => export const getUpdateCheckQuery = () =>
+28
View File
@@ -0,0 +1,28 @@
<script lang="ts">
import { AlertTriangle, Home, RotateCw } from 'lucide-svelte';
import { page } from '$app/state';
</script>
<svelte:head>
<title>Error - MusicSeerr</title>
</svelte:head>
<div class="w-full px-2 sm:px-4 lg:px-8 py-4 sm:py-8 max-w-7xl mx-auto">
<div class="flex flex-col items-center justify-center py-20 gap-4 text-center">
<AlertTriangle class="h-16 w-16 text-error/40" />
<h1 class="text-lg font-semibold text-base-content/80">Something went wrong</h1>
<p class="text-sm text-base-content/60">
{page.error?.message ?? 'An unexpected error occurred'}
</p>
<div class="flex items-center gap-2">
<a href="/" class="btn btn-ghost btn-sm">
<Home class="h-4 w-4" />
Home
</a>
<button class="btn btn-accent btn-sm" onclick={() => location.reload()}>
<RotateCw class="h-4 w-4" />
Retry
</button>
</div>
</div>
</div>