Fix TRV control routes hanging up to ~93min, causing Gateway Time-out
Both POST /api/devices/:id/trv-control and POST /api/zones/:id/override awaited the full setTargetWithRetry()/batchSetZoneTemperature() retry/backoff pipeline before responding -- up to ~93 minutes (RETRY_DELAYS_MS sums to 5610s across 10 attempts). Any reverse proxy times out its own connection long before that finishes, surfacing as a real Gateway Time-out (hit 2026-08-26 testing a TRV setpoint change -- confirmed not kiosk-specific, same code path every TRV control UI goes through, including kiosk's bulk edit which compounded it per selected device). Fix: both routes now fire the retry pipeline in the background and respond immediately (ok:true, pending:true) -- same eventually-consistent pattern the MHI/Daikin panels already use (fire command, poll status separately for the real outcome). Updated callers that read the old synchronous successful/total counts (ZoneDetailModal's override message, KioskBulkPanel's TRV result message) to reflect 'sent, applying in the background' instead. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
f3a73ad273
commit
55afcaa786
5 changed files with 50 additions and 22 deletions
|
|
@ -50,7 +50,11 @@ export default function KioskBulkPanel({ devices, onDone }: Props) {
|
|||
await new Promise(r => setTimeout(r, TRV_STAGGER_MS))
|
||||
}
|
||||
setApplyingTrv(false)
|
||||
setResults(r => [...r, `TRVs: ${trvIds.length - failed}/${trvIds.length} updated${failed ? ' — some failed' : ''}`])
|
||||
// The backend now fires each TRV's retry/backoff pipeline in the background
|
||||
// rather than blocking on it (see routes/override.js) — this only confirms the
|
||||
// command was SENT, not that the valve has actually acknowledged it yet. Check
|
||||
// the zone tiles' setpoint a little later for the real outcome.
|
||||
setResults(r => [...r, `TRVs: sent to ${trvIds.length - failed}/${trvIds.length}${failed ? ' — some failed to send' : ''} — applying in the background`])
|
||||
}
|
||||
|
||||
async function applyAc() {
|
||||
|
|
|
|||
|
|
@ -23,8 +23,12 @@ function timeAgo(iso: string | null | undefined): string {
|
|||
// displayed value immediately but the MQTT command is debounced 1s after the last
|
||||
// click — these are battery/deep-sleep valves going through the full retry/backoff
|
||||
// pipeline (setTargetWithRetry), so rapid-fire clicking shouldn't fire a command per
|
||||
// click. Read side is push-populated (mqtt.js keeps the row fresh from
|
||||
// shellies/+/status + shellies/+/info), same "read the row" shape as Mhi/Daikin panels.
|
||||
// click. That retry pipeline runs in the backend background now (routes/override.js),
|
||||
// not awaited by the HTTP response — sendTrvControl() resolving ok:true only means
|
||||
// the command was sent, not that the valve has acknowledged it yet. Read side is
|
||||
// push-populated (mqtt.js keeps the row fresh from shellies/+/status +
|
||||
// shellies/+/info), same "read the row" shape as Mhi/Daikin panels — refresh (the
|
||||
// button below) to see the real outcome once the valve responds.
|
||||
export default function TrvControlPanel({ deviceId, canControl }: { deviceId: number; canControl: boolean }) {
|
||||
const [loading, setLoading] = useState(true)
|
||||
const [error, setError] = useState('')
|
||||
|
|
|
|||
|
|
@ -134,7 +134,7 @@ export default function ZoneDetailModal({ zone, onClose, onSaved }: {
|
|||
try {
|
||||
const res = await overrideZone(zone.id, Number(overrideTemp))
|
||||
if (res.ok) {
|
||||
setMsg(`Set to ${overrideTemp}°C (${res.successful}/${res.total} devices) — auto mode disabled`)
|
||||
setMsg(`Sent ${overrideTemp}°C to ${res.total} device${res.total === 1 ? '' : 's'} — applying in the background, auto mode disabled`)
|
||||
setAutoMode(false)
|
||||
onSaved()
|
||||
} else {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue