[webapp] Add retry logic and improve renderer registration

- Added automatic retries with exponential backoff to fetchRenderers
- Improved WebRenderer registration: handle stale players, avoid duplicate registrations,
  and force renderers refresh after successful connection
- Bumped version to v0.3.37 (Cargo: 0.3.36 → Cargo.lock mismatch fixed by updating to final version)
This commit is contained in:
2026-04-06 00:08:50 +02:00
parent 23b1ce7661
commit 19451068f1
5 changed files with 68 additions and 27 deletions

2
Cargo.lock generated
View File

@@ -4,7 +4,7 @@ version = 4
[[package]] [[package]]
name = "PMOMusic" name = "PMOMusic"
version = "0.3.35" version = "0.3.36"
dependencies = [ dependencies = [
"axum 0.8.7", "axum 0.8.7",
"console-subscriber", "console-subscriber",

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "PMOMusic" name = "PMOMusic"
version = "0.3.35" version = "0.3.37"
edition = "2024" edition = "2024"
[dependencies] [dependencies]

View File

@@ -270,30 +270,40 @@ function selectRenderer(id: string | null) {
snapshotState.selectedRendererId = id; snapshotState.selectedRendererId = id;
} }
async function fetchRenderers(force = false) { async function fetchRenderers(force = false, retries = 2) {
ensureSSEInitialized(); ensureSSEInitialized();
try { let lastError: Error | null = null;
loading.value = true;
error.value = null; for (let attempt = 0; attempt <= retries; attempt++) {
try {
loading.value = true;
error.value = null;
// Utiliser le cache API centralisé // Utiliser le cache API centralisé
const data = await apiCache.fetch( const data = await apiCache.fetch(
'/renderers', '/renderers',
undefined, undefined,
() => api.getRenderers(), () => api.getRenderers(),
{ force, ttl: RENDERERS_CACHE_MS } { force, ttl: RENDERERS_CACHE_MS }
); );
renderersCache.value = new Map( renderersCache.value = new Map(
data.map((renderer) => [renderer.id, renderer]), data.map((renderer) => [renderer.id, renderer]),
); );
} catch (err) { return;
error.value = err instanceof Error ? err.message : "Erreur fetch renderers"; } catch (err) {
console.error("[useRenderers] Erreur fetch:", err); lastError = err instanceof Error ? err : new Error("Erreur fetch renderers");
} finally { console.error("[useRenderers] Erreur fetch (attempt " + (attempt + 1) + "):", lastError);
loading.value = false; if (attempt < retries) {
await new Promise(r => setTimeout(r, 500 * (attempt + 1)));
}
} finally {
loading.value = false;
}
} }
error.value = lastError?.message ?? "Erreur fetch renderers";
} }
async function fetchRendererSnapshot( async function fetchRendererSnapshot(

View File

@@ -73,17 +73,41 @@ export function useWebRenderer() {
let onConnectedCallback: (() => void) | null = null; let onConnectedCallback: (() => void) | null = null;
async function register(): Promise<void> { async function register(): Promise<void> {
// Prevent concurrent registrations (race condition → double player) // Allow re-registration if we have a stale player but no connection
if (globalPlayer || registering) { if (globalPlayer && !connected.value) {
console.log('[WebRenderer] stale globalPlayer, clearing');
globalPlayer = null;
}
if (globalPlayer) {
player = globalPlayer;
connected.value = true;
console.log('[WebRenderer] reusing existing player');
return;
}
if (registering) {
console.log('[WebRenderer] already registering, waiting...');
// Wait a bit and try once
await new Promise(r => setTimeout(r, 1000));
if (globalPlayer) { if (globalPlayer) {
player = globalPlayer; player = globalPlayer;
connected.value = true; connected.value = true;
return;
} }
return;
} }
registering = true; registering = true;
const instanceId = getOrCreateInstanceId(); let instanceId;
try {
instanceId = getOrCreateInstanceId();
} catch (e) {
console.error('[WebRenderer] failed to get instanceId:', e);
registering = false;
return;
}
console.log('[WebRenderer] registering with instanceId:', instanceId); console.log('[WebRenderer] registering with instanceId:', instanceId);
try { try {
@@ -122,6 +146,13 @@ export function useWebRenderer() {
connected.value = true; connected.value = true;
onConnectedCallback?.(); onConnectedCallback?.();
// Force refresh renderers list after registration
// The SSE might miss the initial event
setTimeout(() => {
console.log('[WebRenderer] forcing renderers refresh');
window.dispatchEvent(new CustomEvent('webrenderer-registered'));
}, 500);
} catch (e) { } catch (e) {
console.error("[WebRenderer] register error:", e); console.error("[WebRenderer] register error:", e);
} finally { } finally {

View File

@@ -1 +1 @@
0.3.35 0.3.37