fixed race condition on web socket status updates

This commit is contained in:
Carter 2026-03-13 15:47:22 -06:00
parent 50103d5a0c
commit a2ac900f3e

View file

@ -32,6 +32,28 @@ import { cloneDeep } from "lodash";
import LoadingScreen from "app/LoadingScreen";
import TeamDialog from "teams/TeamDialog";
type TimestampedReading = {
timestamp?: string;
};
const getTimestampMillis = (timestamp?: string): number | undefined => {
if (!timestamp) return undefined;
const parsed = Date.parse(timestamp);
return Number.isNaN(parsed) ? undefined : parsed;
};
const pickNewestReading = <T extends TimestampedReading>(
current: T | null | undefined,
incoming: T | null | undefined
): T | null | undefined => {
const currentTs = getTimestampMillis(current?.timestamp);
const incomingTs = getTimestampMillis(incoming?.timestamp);
if (incomingTs === undefined) return current ?? incoming;
if (currentTs === undefined) return incoming ?? current;
return incomingTs >= currentTs ? incoming : current;
};
const useStyles = makeStyles((theme: Theme) => {
return ({
buttonBox: {
@ -212,7 +234,31 @@ export default function Devices() {
prev.map((d) => {
if (d.id().toString() !== deviceId) return d
const updated = Device.clone(d)
updated.status = status
const incomingStatus = pond.DeviceStatus.fromObject(status)
const currentStatus = d.status ?? pond.DeviceStatus.create()
// Guard against out-of-order websocket events by keeping whichever
// reading has the newest timestamp for each independently-updated sensor.
incomingStatus.plenum = pickNewestReading(currentStatus.plenum, incomingStatus.plenum)
incomingStatus.sen5x = pickNewestReading(currentStatus.sen5x, incomingStatus.sen5x)
incomingStatus.co = pickNewestReading(currentStatus.co, incomingStatus.co)
incomingStatus.co2 = pickNewestReading(currentStatus.co2, incomingStatus.co2)
incomingStatus.no2 = pickNewestReading(currentStatus.no2, incomingStatus.no2)
incomingStatus.o2 = pickNewestReading(currentStatus.o2, incomingStatus.o2)
incomingStatus.lel = pickNewestReading(currentStatus.lel, incomingStatus.lel)
incomingStatus.h2s = pickNewestReading(currentStatus.h2s, incomingStatus.h2s)
const currentLastActive = getTimestampMillis(currentStatus.lastActive)
const incomingLastActive = getTimestampMillis(incomingStatus.lastActive)
if (
currentLastActive !== undefined &&
incomingLastActive !== undefined &&
incomingLastActive < currentLastActive
) {
incomingStatus.lastActive = currentStatus.lastActive
}
updated.status = incomingStatus
return updated
})
)