Skip to content

Commit

Permalink
[#230] GC non-terminating websocket conns
Browse files Browse the repository at this point in the history
If a WebSocket connection is closed without normal termination (e.g. as caused
by sudden loss of power, airplane mode, etc.) - it can hang around in conns_
for an extended period of time until the underlying TCP connection is identified
as dead.

This simple mod allows Sente's server to perform WebSocket connection GC for
clients that haven't communicated with the server w/in a defined amount of time
(must be > client :ws-kalive-ms).

Big thanks to @altV for helping to catch + diagnose this issue.
  • Loading branch information
ptaoussanis committed May 11, 2016
1 parent b70815e commit 35658d0
Showing 1 changed file with 27 additions and 4 deletions.
31 changes: 27 additions & 4 deletions src/taoensso/sente.cljx
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@
:handshake-data-fn ; (fn [ring-req]) -> arb user data to append to handshake evs.
:send-buf-ms-ajax ; [2]
:send-buf-ms-ws ; [2]
:ws-conn-gc-ms ; Should be > client's :ws-kalive-ms
:packer ; :edn (default), or an IPacker implementation (experimental).
[1] e.g. `taoensso.sente.server-adapters.http-kit/http-kit-adapter` or
Expand All @@ -249,11 +250,12 @@
after send call (larger values => larger batch windows)."

[web-server-adapter ; Actually a server-ch-adapter, but that may be confusing
& [{:keys [recv-buf-or-n send-buf-ms-ajax send-buf-ms-ws
& [{:keys [recv-buf-or-n send-buf-ms-ajax send-buf-ms-ws ws-conn-gc-ms
user-id-fn csrf-token-fn handshake-data-fn packer]
:or {recv-buf-or-n (async/sliding-buffer 1000)
send-buf-ms-ajax 100
send-buf-ms-ws 30
ws-conn-gc-ms (enc/ms :secs 60)
user-id-fn (fn [ring-req] (get-in ring-req [:session :uid]))
csrf-token-fn (fn [ring-req]
(or (get-in ring-req [:session :csrf-token])
Expand All @@ -274,6 +276,8 @@
connected-uids_ (atom {:ws #{} :ajax #{} :any #{}})
send-buffers_ (atom {:ws {} :ajax {}}) ; {<uid> [<buffered-evs> <#{ev-uuids}>]}

last-ws-msg-udts_ (atom {}) ; {<client-id> <udt>}, used for ws conn gc

user-id-fn
(fn [ring-req client-id]
;; Allow uid to depend (in part or whole) on client-id. Be cautious
Expand Down Expand Up @@ -485,12 +489,29 @@
(fn [server-ch]
(if websocket?
(do ; WebSocket handshake

(tracef "New WebSocket channel: %s (%s)"
uid (str server-ch)) ; _Must_ call `str` on server-ch
(reset-in! conns_ [:ws uid client-id] server-ch)
(when (connect-uid! :ws uid)
(receive-event-msg! [:chsk/uidport-open]))
(handshake! server-ch))
(handshake! server-ch)

;; Start ws conn gc loop
;; Sudden abnormal disconnects (e.g. enabling airplane
;; mode) prevent the conn from firing the normal
;; :on-close event until only much later (determined by
;; TCP settings).
(swap! last-ws-msg-udts_ (fn [m] (assoc m client-id (enc/now-udt))))
(when-let [ms ws-conn-gc-ms]
(go-loop []
(when-let [last-ws-msg-udt* (get @last-ws-msg-udts_ client-id)]
(<! (async/timeout ms))
(when-let [last-ws-msg-udt (get @last-ws-msg-udts_ client-id)]
(if (= last-ws-msg-udt last-ws-msg-udt*)
;; No activity since last timeout => conn dead
(interfaces/sch-close! server-ch)
(recur)))))))

;; Ajax handshake/poll connection:
(let [initial-conn-from-client?
Expand All @@ -508,6 +529,7 @@

:on-msg ; Only for WebSockets
(fn [server-ch req-ppstr]
(swap! last-ws-msg-udts_ (fn [m] (assoc m client-id (enc/now-udt))))
(let [[clj ?cb-uuid] (unpack packer req-ppstr)]
(receive-event-msg! clj ; Should be ev
(when ?cb-uuid
Expand All @@ -524,6 +546,7 @@

(if websocket?
(do ; WebSocket close
(swap! last-ws-msg-udts_ (fn [m] (dissoc m client-id)))
(swap-in! conns_ [:ws uid]
(fn [?m]
(let [new-m (dissoc ?m client-id)]
Expand Down Expand Up @@ -1050,8 +1073,8 @@
:as opts
:or {type :auto
recv-buf-or-n (async/sliding-buffer 2048) ; Mostly for buffered-evs
ws-kalive-ms 25000 ; < Heroku 30s conn timeout
lp-timeout-ms 25000 ; ''
ws-kalive-ms (enc/ms :secs 25) ; < Heroku 30s conn timeout
lp-timeout-ms (enc/ms :secs 25) ; ''
packer :edn
client-id (or (:client-uuid opts) ; Backwards compatibility
(enc/uuid-str))
Expand Down

1 comment on commit 35658d0

@altV
Copy link

@altV altV commented on 35658d0 May 11, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thank you!

Please sign in to comment.