fix(17): flush HTTP response before SSE publish to fix own-message alignment race
The server was publishing to the SSE broker before writing the HTMX response, causing a race: if the SSE event (IsOwn=false, left-aligned) arrived at the browser before HTMX appended the response (IsOwn=true, right-aligned), the SSE path won and messageExists() then blocked the correct HTMX append. Fix: write and flush the HTMX response first, then publish to SSE. This ensures the sender's own message lands in the DOM right-aligned before the SSE event fires. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
30256895b2
commit
96a58ef0ea
1 changed files with 14 additions and 5 deletions
|
|
@ -125,6 +125,18 @@ func DiscussionMessageCreateHandler(deps DiscussionDeps) http.HandlerFunc {
|
||||||
message := templates.DiscussionMessageFromRow(row, user.ID)
|
message := templates.DiscussionMessageFromRow(row, user.ID)
|
||||||
data := templates.DiscussionTabData{Messages: []templates.DiscussionMessageView{message}}
|
data := templates.DiscussionTabData{Messages: []templates.DiscussionMessageView{message}}
|
||||||
markDiscussionRead(r, deps.Queries, tablo, user.ID, data)
|
markDiscussionRead(r, deps.Queries, tablo, user.ID, data)
|
||||||
|
|
||||||
|
// Send HTTP response before publishing to SSE so the HTMX append (IsOwn=true)
|
||||||
|
// lands in the DOM before the SSE event fires. This prevents the race where SSE
|
||||||
|
// wins, appends IsOwn=false, and messageExists() then blocks the HTMX append.
|
||||||
|
if r.Header.Get("HX-Request") == "true" {
|
||||||
|
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||||
|
_ = templates.DiscussionMessageRow(message).Render(r.Context(), w)
|
||||||
|
if f, ok := w.(http.Flusher); ok {
|
||||||
|
f.Flush()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if deps.Realtime != nil {
|
if deps.Realtime != nil {
|
||||||
// SSE recipients are never the author — always render as IsOwn: false.
|
// SSE recipients are never the author — always render as IsOwn: false.
|
||||||
sseMessage := message
|
sseMessage := message
|
||||||
|
|
@ -143,14 +155,11 @@ func DiscussionMessageCreateHandler(deps DiscussionDeps) http.HandlerFunc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.Header.Get("HX-Request") == "true" {
|
if r.Header.Get("HX-Request") != "true" {
|
||||||
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
|
||||||
_ = templates.DiscussionMessageRow(message).Render(r.Context(), w)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
http.Redirect(w, r, templates.DiscussionURL(tablo.ID), http.StatusSeeOther)
|
http.Redirect(w, r, templates.DiscussionURL(tablo.ID), http.StatusSeeOther)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func DiscussionStreamHandler(deps DiscussionDeps) http.HandlerFunc {
|
func DiscussionStreamHandler(deps DiscussionDeps) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue