mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-10-18 21:47:39 +02:00
Root cause: Frontend was firing multiple concurrent PUT requests when toggling MQTT, causing SQLite "database is locked" errors after 6-second timeout.
Fixes: 1. frontend/src/pages/SettingsPage.tsx - Added isSavingRef to prevent concurrent saves while a mutation is in progress 2. backend/app/services/mqtt_relay.py - Added 3-second timeout for MQTT connect to prevent blocking on unreachable brokers
This commit is contained in:
@@ -92,11 +92,17 @@ class MQTTRelayService:
|
||||
self.client.tls_set(cert_reqs=ssl.CERT_NONE)
|
||||
self.client.tls_insecure_set(True) # Allow self-signed certs
|
||||
|
||||
# Connect (non-blocking with loop_start)
|
||||
self.client.connect_async(broker, port, keepalive=60)
|
||||
# Run connect_async in thread pool with timeout to avoid blocking
|
||||
# on unreachable brokers (connect_async does synchronous socket creation)
|
||||
try:
|
||||
await asyncio.wait_for(asyncio.to_thread(self.client.connect_async, broker, port, 60), timeout=3.0)
|
||||
except TimeoutError:
|
||||
logger.warning(f"MQTT relay connection to {broker}:{port} timed out")
|
||||
return False
|
||||
|
||||
self.client.loop_start()
|
||||
|
||||
# Wait briefly for connection
|
||||
# Wait briefly for connection callback
|
||||
await asyncio.sleep(1.0)
|
||||
|
||||
if self.connected:
|
||||
|
||||
@@ -300,6 +300,7 @@ export function SettingsPage() {
|
||||
|
||||
// Ref for debounce timeout
|
||||
const saveTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
||||
const isSavingRef = useRef(false);
|
||||
const isInitialLoadRef = useRef(true);
|
||||
|
||||
// Sync local state when settings load
|
||||
@@ -324,6 +325,10 @@ export function SettingsPage() {
|
||||
onError: (error: Error) => {
|
||||
showToast(`Failed to save: ${error.message}`, 'error');
|
||||
},
|
||||
onSettled: () => {
|
||||
// Reset saving flag when mutation completes (success or error)
|
||||
isSavingRef.current = false;
|
||||
},
|
||||
});
|
||||
|
||||
// Debounced auto-save when localSettings change
|
||||
@@ -369,6 +374,11 @@ export function SettingsPage() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't queue more saves while one is in progress
|
||||
if (isSavingRef.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear existing timeout
|
||||
if (saveTimeoutRef.current) {
|
||||
clearTimeout(saveTimeoutRef.current);
|
||||
@@ -376,6 +386,11 @@ export function SettingsPage() {
|
||||
|
||||
// Set new debounced save (500ms delay)
|
||||
saveTimeoutRef.current = setTimeout(() => {
|
||||
// Skip if a save is already in progress
|
||||
if (isSavingRef.current) {
|
||||
return;
|
||||
}
|
||||
isSavingRef.current = true;
|
||||
// Only send the fields we manage on this page (exclude virtual_printer_* which are managed separately)
|
||||
const settingsToSave: AppSettingsUpdate = {
|
||||
auto_archive: localSettings.auto_archive,
|
||||
|
||||
File diff suppressed because one or more lines are too long
+1
-1
@@ -23,7 +23,7 @@
|
||||
|
||||
<!-- Splash screens for iOS -->
|
||||
<link rel="apple-touch-startup-image" href="/img/android-chrome-512x512.png" />
|
||||
<script type="module" crossorigin src="/assets/index-Yr6VeTyb.js"></script>
|
||||
<script type="module" crossorigin src="/assets/index-BEswNysN.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-Dzh7xD3q.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -15,4 +15,9 @@ git add .
|
||||
git commit -m "Updated Wiki"
|
||||
git push
|
||||
|
||||
cd ../spoolbuddy-website
|
||||
git add .
|
||||
git commit -m "Updated website"
|
||||
git push
|
||||
|
||||
cd ../bambuddy
|
||||
|
||||
Reference in New Issue
Block a user