fix: a stalled server no longer reads as "your clock is ahead"
CI / Build & Quality Checks (pull_request) Successful in 3m1s
CI / Trigger Desktop Build (pull_request) Skipped
CI / Docker image build & smoke test (pull_request) Skipped
CI / Secret scan (gitleaks) (pull_request) Successful in 7s
CI / Playwright smoke (e2e) (pull_request) Failing after 11m28s
CI / Build & Quality Checks (pull_request) Successful in 3m1s
CI / Trigger Desktop Build (pull_request) Skipped
CI / Docker image build & smoke test (pull_request) Skipped
CI / Secret scan (gitleaks) (pull_request) Successful in 7s
CI / Playwright smoke (e2e) (pull_request) Failing after 11m28s
Incident 2026-09-29: the homeserver's host ran out of memory and stalled for ~2 minutes. The /sync that finally went out carried events whose `age` was computed ~30 s before it arrived, so every client showed "Your computer's clock is 30 seconds ahead of the server" while the real problem was the server (all host clocks were within 0.25 s the whole evening). The skew estimate was the median of the last 5 samples, and a sample is local skew + delivery delay, so one late /sync with a handful of events tripped it. - Estimate = the LOWEST sample of the last 5 minutes: delay only ever adds, so the fastest-delivered event is the truest. - "Behind" (which a delay can't cause) is reported as soon as there are 3 samples, like before. "Ahead" must hold across samples received at least a minute apart, so a single late burst never trips it. - Samples are aged on the monotonic clock, and a change of the local clock (someone fixing it) resets the measurement, so the warning clears at once. - Only events stamped by our own homeserver are sampled: a federated event's origin_server_ts is the other server's clock. - Wording: "This device's clock is … Voice calls and encrypted messages can fail until it's corrected." / call bar "Device clock … : calls may fail" (was "will fail"). Unit tests: the incident (late burst after normal traffic, and a fresh client whose first samples are all late), mixed slow/fast deliveries, ahead only after a minute, behind at once, hysteresis, clock fixed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
c0c93213c1
commit
bb569d69a2
@@ -1071,6 +1071,10 @@ function ClockSkewFeature() {
|
||||
data,
|
||||
) => {
|
||||
if (!data.liveEvent) return;
|
||||
// Only events our homeserver stamped: a federated event's
|
||||
// origin_server_ts is the other server's clock.
|
||||
const senderServer = mEvent.getSender()?.split(':').slice(1).join(':');
|
||||
if (senderServer !== mx.getDomain()) return;
|
||||
monitor.sample(mEvent.getTs(), mEvent.getAge(), mEvent.localTimestamp);
|
||||
};
|
||||
mx.on(RoomEvent.Timeline, onTimeline);
|
||||
|
||||
@@ -19,7 +19,7 @@ const readDismissedUntil = (): number => {
|
||||
};
|
||||
|
||||
/**
|
||||
* [Gitea #158] "Your computer's clock is 14 minutes ahead of the server."
|
||||
* [Gitea #158] "This device's clock is 14 minutes ahead of the server."
|
||||
* Same slot and style as the sync banners. Shown while the skew monitor is
|
||||
* over its threshold; the direction matters, so it is said. Dismissable for
|
||||
* 24 h; never auto-corrects anything.
|
||||
@@ -53,8 +53,8 @@ export function ClockSkewBanner() {
|
||||
>
|
||||
<Box alignItems="Center" gap="300" wrap="Wrap" justifyContent="Center">
|
||||
<Text size="L400" align="Center">
|
||||
Your computer's clock is <b>{describeSkewVsServer(skewMs)}</b>. Encrypted messages
|
||||
and voice calls will fail until it is fixed.
|
||||
This device's clock is <b>{describeSkewVsServer(skewMs)}</b>. Voice calls and
|
||||
encrypted messages can fail until it's corrected.
|
||||
</Text>
|
||||
<Button
|
||||
size="300"
|
||||
|
||||
Reference in New Issue
Block a user