luminus 2022-02-11

Hi, I’m trying to set up https://github.com/luminus-framework/jdbc-ring-session in my Luminus-based app, but have problems creating the session store. The line

(def session-store (jdbc-store (env :database-url)))
in clj/db/core.clj is causing exception
Caused by: java.lang.ClassCastException: class mount.core.DerefableState cannot be cast to class clojure.lang.IFn (mount.core.DerefableState is in unnamed module of loader clojure.lang.DynamicClassLoader @61799544; clojure.lang.IFn is in unnamed module of loader 'app')
        at clojure.lang.Compiler$InvokeExpr.eval(Compiler.java:3702)
        ... 122 more
What am I doing wrong?

Not a lot of context, but I see that error message sometimes if a mount component was not initialized, so I assume that’s what happened to the component you are trying to reference with env?

Oh okay, well then env seem not to be initialized

(defstate env
  :start
  (load-config
    :merge
    [(args)
     (source/from-system-props)
     (source/from-env)]))

Did env work for other components? What do you see if you type (start) in the user ns in your REPL?

Right now the application REPL does not come up. I think what I am doing wrong here is to use env before the application is started, because of the (static?) definition of (def session-store (jdbc-store (env :database-url)))

Exception in thread "main" Syntax error macroexpanding at (core.clj:25:32).
	at clojure.lang.Compiler$InvokeExpr.eval(Compiler.java:3711)
	at clojure.lang.Compiler$InvokeExpr.eval(Compiler.java:3705)
...
	at clojure.lang.RT.init(RT.java:467)
	at clojure.main.main(main.java:38)
Caused by: java.lang.ClassCastException: class mount.core.DerefableState cannot be cast to class clojure.lang.IFn (mount.core.DerefableState is in unnamed module of loader clojure.lang.DynamicClassLoader @61799544; clojure.lang.IFn is in unnamed module of loader 'app')
	at clojure.lang.Compiler$InvokeExpr.eval(Compiler.java:3702)
	... 122 more

Ah yes, I did not think about that 🙂 The def is loaded on ns-initialization, before (start), you are right.

I just checked in one of our applications, we just add it to our wrap-base function in the project-name.middleware namespace

(defn wrap-base [handler]
  (-> ((:middleware defaults) handler)
      (wrap-idle-session-timeout {:timeout (* 30 60)
                                  :timeout-response {:status 200
                                                     :body "Session timed out"}})
      (wrap-defaults
        (-> site-defaults
            (assoc-in [:security :anti-forgery] false)
            (assoc-in  [:session :store] (jdbc-store (:datasource *db*)))))
      wrap-internal-error))

Which might look different than yours, of course

Ah okay, that makes sense. Then it’s within the function and will be executed then the app is running. Also you’re passing *db* instead of the connection url, which probably makes sense to use the same connection pool…?!

Yes, that’s correct

Cool, that works! Thank you very much, you saved me a lot of time 🙂

Happy to hear that 🙂

Btw. I will shamelessly copy that wrap-idle-session-timeout - that solves another item on my todo list 😉

Feel free 😄

When persisting sessions using https://github.com/luminus-framework/jdbc-ring-session the following exception is thrown:

2022-02-11 10:39:04,743 [worker-2] ERROR payroll.middleware - Unfreezable type: class next.jdbc.result_set$navize_row$fn__21563 
clojure.lang.ExceptionInfo: Unfreezable type: class next.jdbc.result_set$navize_row$fn__21563
        at taoensso.nippy$throw_unfreezable.invokeStatic(nippy.clj:1003)
        at taoensso.nippy$throw_unfreezable.invoke(nippy.clj:1000)
Could this be caused by certain objects in the session which are not serializable or something like that?

Yes, nippy cannot handle that type. I’m wondering why it gets this type, however. Does jdbc-ring-session write values into the db for you?

Well each session is written to the db, serialized as blob, or what do you mean?

Yes, so writing works, but reloading from the db does not?

Ah sorry, I misunderstood. No, it is not writing. Above exception occurs when the first session is about to be written.

I’m implementing ‘logout’ for a basic web app. Has anyone else seen a difference between (assoc session :identity nil) vs (dissoc session :identity) ? It seems to me that dissoc doesn’t really clear the identity in the session, but I’m not clear on why.