From 3e8c715de81dc5879b2dda1bc43f821b29f12c4b Mon Sep 17 00:00:00 2001 From: Naiyuan Qing <145280634+NevilleQingNY@users.noreply.github.com> Date: Tue, 31 Mar 2026 11:25:41 +0800 Subject: [PATCH] feat(realtime): skip WS refetch for self-triggered events Backend WS messages now include actor_id from the Event struct. Frontend useRealtimeSync skips the debounced refetch when the event was triggered by the current user, eliminating unnecessary re-renders of heavy components (~400ms after each user action). Co-Authored-By: Claude Opus 4.6 (1M context) --- apps/web/features/realtime/use-realtime-sync.ts | 5 +++++ apps/web/shared/types/events.ts | 1 + server/cmd/server/listeners.go | 9 +++++---- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/apps/web/features/realtime/use-realtime-sync.ts b/apps/web/features/realtime/use-realtime-sync.ts index 8a16c5c2..bb6f0d54 100644 --- a/apps/web/features/realtime/use-realtime-sync.ts +++ b/apps/web/features/realtime/use-realtime-sync.ts @@ -68,6 +68,11 @@ export function useRealtimeSync(ws: WSClient | null) { }; const unsubAny = ws.onAny((msg) => { + const myUserId = useAuthStore.getState().user?.id; + if (msg.actor_id && msg.actor_id === myUserId) { + logger.debug("skipping self-event", msg.type); + return; + } const prefix = msg.type.split(":")[0] ?? ""; const refresh = refreshMap[prefix]; if (refresh) debouncedRefresh(prefix, refresh); diff --git a/apps/web/shared/types/events.ts b/apps/web/shared/types/events.ts index aac9f0a9..304a28ee 100644 --- a/apps/web/shared/types/events.ts +++ b/apps/web/shared/types/events.ts @@ -47,6 +47,7 @@ export type WSEventType = export interface WSMessage { type: WSEventType; payload: T; + actor_id?: string; } export interface IssueCreatedPayload { diff --git a/server/cmd/server/listeners.go b/server/cmd/server/listeners.go index 3410e5b6..1d484dfb 100644 --- a/server/cmd/server/listeners.go +++ b/server/cmd/server/listeners.go @@ -30,7 +30,7 @@ func registerListeners(bus *events.Bus, hub *realtime.Hub) { if recipientID == "" { return } - data, err := json.Marshal(map[string]any{"type": e.Type, "payload": e.Payload}) + data, err := json.Marshal(map[string]any{"type": e.Type, "payload": e.Payload, "actor_id": e.ActorID}) if err != nil { return } @@ -87,7 +87,7 @@ func registerListeners(bus *events.Bus, hub *realtime.Hub) { if userID == "" { return } - data, err := json.Marshal(map[string]any{"type": e.Type, "payload": e.Payload}) + data, err := json.Marshal(map[string]any{"type": e.Type, "payload": e.Payload, "actor_id": e.ActorID}) if err != nil { return } @@ -102,8 +102,9 @@ func registerListeners(bus *events.Bus, hub *realtime.Hub) { } msg := map[string]any{ - "type": e.Type, - "payload": e.Payload, + "type": e.Type, + "payload": e.Payload, + "actor_id": e.ActorID, } data, err := json.Marshal(msg) if err != nil {