Search code examples
clojureringcompojure

Ring session being reset with each save (Compojure)


Each time I save a Clojure source file in Ring project, the session resets.

Note the ring-session ids. I preceded each by saving my handler.clj file:

2015-03-17 11:02:51,857 INFO  onelog.core: Starting :get / for 127.0.0.1 {"accept-encoding" "gzip, deflate, sdch", "cache-control" "max-age=0", "connection" "keep-alive", "user-agent" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.76 Safari/537.36", "accept-language" "en-US,en;q=0.8", "accept" "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", "host" "localhost:3000", "cookie" "ring-session=40575c9e-fbe9-4fd5-8624-d5e4ef9d98a9"}
2015-03-17 11:02:51,859 INFO  onelog.core: Finished :get / for 127.0.0.1 in (2 ms) Status: 404
2015-03-17 11:03:01,147 INFO  onelog.core: Starting :get / for 127.0.0.1 {"accept-encoding" "gzip, deflate, sdch", "cache-control" "max-age=0", "connection" "keep-alive", "user-agent" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.76 Safari/537.36", "accept-language" "en-US,en;q=0.8", "accept" "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", "host" "localhost:3000", "cookie" "ring-session=26aadcce-e665-43df-afa5-0f09f98351ac"}
2015-03-17 11:03:01,149 INFO  onelog.core: Finished :get / for 127.0.0.1 in (2 ms) Status: 404

It can get onerous if you're working with a logged in user, only to have to re-login each time you make a change.

Here's what's in my handler:

(def app
  (-> app-routes
      (friend/authenticate auth-config)
      (wrap-defaults site-defaults)  
      (logger/wrap-with-logger)))

Am I missing something obvious?


Solution

  • You are probably instantiating a new session store when you create (def) your handler. There are multiple ways of solving the problem. A direct method is to use defonce to define a single session store and reuse it when creating new handlers. That will cause issues if you need multiple independent handlers (for testing etc). Look into components for a more comprehensive solution.

    After update of OP:

    (wrap-defaults req site-defaults) here creates a new (in-memory, empty) session store at every evaluation, so all your old sessions will be invalidated whenever (def app ...) is called.

    On easy solution is to use something like

    (defonce app
      (-> #'app-routes ;; reevaluate app-routes at every request
          (friend/authenticate auth-config)
          (wrap-defaults site-defaults)  
          (logger/wrap-with-logger)))
    

    Which makes it possible to load the file containing app without resetting the sessions, at the cost of making it slightly more fiddly to add middleware.

    More involved alternatives include using a durable (disk, database, memcached etc) or pure-cookie based (client-side) session store that won't get emptied when reloading the wrap-defaults. See the documentation for wrap-defaults and ring.middleware.session