mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-22 15:06:43 +02:00
fix(sync): fix SSE live updates — 2 bugs found during E2E testing
Bug 1: NotifyUser() early-returned when no WebSocket clients existed, skipping SSE subscriber notifications entirely. Fixed by restructuring to check WS clients and SSE subscribers independently. Bug 2: SSE stream cursor defaulted to client's `since` parameter when no initial data existed. If `since` was in the future (or very recent), live updates had created_at < cursor and were silently filtered out. Fixed by defaulting cursor to now() when no initial data is returned. Bug 3: NotifyUser used original sseSubs slice instead of sseSubsCopy after releasing the read lock (race condition). Verified E2E: Push from client A → SSE stream on client B receives live change event with correct data within ~1 second. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
4cb1bda852
commit
fed38efb8b
2 changed files with 41 additions and 38 deletions
|
|
@ -164,7 +164,7 @@ func (h *Handler) HandleSync(w http.ResponseWriter, r *http.Request) {
|
|||
SyncedUntil: now,
|
||||
}
|
||||
|
||||
// Notify other connected clients via WebSocket
|
||||
// Notify other connected clients via WebSocket/SSE
|
||||
if len(affectedTables) > 0 {
|
||||
tables := make([]string, 0, len(affectedTables))
|
||||
for t := range affectedTables {
|
||||
|
|
@ -326,7 +326,8 @@ func (h *Handler) HandleStream(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
}
|
||||
|
||||
// Track cursors per collection
|
||||
// Track cursors per collection — default to now() if no initial data
|
||||
now := time.Now().UTC().Format(time.RFC3339Nano)
|
||||
cursors := make(map[string]string)
|
||||
for _, coll := range collections {
|
||||
cursors[coll] = since
|
||||
|
|
@ -337,6 +338,7 @@ func (h *Handler) HandleStream(w http.ResponseWriter, r *http.Request) {
|
|||
changes, err := h.store.GetChangesSince(ctx, userID, appID, coll, since, clientID, batchLimit+1)
|
||||
if err != nil {
|
||||
slog.Error("SSE initial pull failed", "error", err, "collection", coll)
|
||||
cursors[coll] = now // Default to now on error
|
||||
continue
|
||||
}
|
||||
|
||||
|
|
@ -350,6 +352,9 @@ func (h *Handler) HandleStream(w http.ResponseWriter, r *http.Request) {
|
|||
cursors[coll] = cursor
|
||||
sendChangeEvent(w, coll, h.convertChanges(changes), cursor, hasMore)
|
||||
flusher.Flush()
|
||||
} else {
|
||||
// No initial data — set cursor to now so live updates work
|
||||
cursors[coll] = now
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue