[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:
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -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",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "PMOMusic"
|
name = "PMOMusic"
|
||||||
version = "0.3.35"
|
version = "0.3.37"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
0.3.35
|
0.3.37
|
||||||
|
|||||||
Reference in New Issue
Block a user