From ecd836af75faac8677e8d1d24e392fa94067dd17 Mon Sep 17 00:00:00 2001 From: spynup Date: Wed, 22 Jul 2015 12:20:47 -0700 Subject: [PATCH] Listen to CloseNotifier in stream handler. Problem: context.Stream() already listens to the closeNotifier, which gives the impression that context.Stream() will return as soon as a client disconnects. Unfortunately, it doesn't! This example code furthers the impression with the defer closeListener(roomid, listener) which one would expect to be called when a client navigates away, which is not the case. In fact, it's only called on the next message that's sent to the room after said client exits. This is because c.SSEvent("message", <-listener) blocks indefinitely until a message comes in, so will not return and yield to c.Stream()'s select that catches the closeNotify. This means that if a client navigates away, the server never notices and cleans up. Fix: Also listen to CloseNotifier inside stream handler. This causes the step() function to return immediately when the client goes away and allows the cleanup to run. Updating this example should make it more clear, I think! --- examples/realtime-chat/main.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/examples/realtime-chat/main.go b/examples/realtime-chat/main.go index e4b55a0f..61a26419 100644 --- a/examples/realtime-chat/main.go +++ b/examples/realtime-chat/main.go @@ -25,9 +25,15 @@ func stream(c *gin.Context) { listener := openListener(roomid) defer closeListener(roomid, listener) + clientGone := c.Writer.CloseNotify() c.Stream(func(w io.Writer) bool { - c.SSEvent("message", <-listener) - return true + select { + case <-clientGone: + return false + case message := <-listener: + c.SSEvent("message", message) + return true + } }) }