I am getting a "This ResultSet is closed." error on new instances of my Clojure web server application on Heroku. The error occurs on an update! operation (which is not lazy so it is not that problem). Select statements work fine on the same database connection.
The code works on my machine :). It works on a heroku instance created some weeks ago. It fails on newly created instances. I have duplicated the error with a stripped down code version.
Has heroku changed recently? I have been informed that other people saw this error when they had a problem with JDBC pools. Could that be happening here?
This is my test code, minus the requires.
(defn vote-for-paper [db user-id paper-id]
(update! db :votes {:votes 1} ["user_id=? AND paper_id=?" user-id paper-id]))
(defroutes voting
(POST "/vote" [:as {db :connection}] (vote-for-paper db 1 2)))
(defn make-wrap-db [db-url]
(fn [handler]
(fn [req]
(with-db-connection [db {:connection-uri db-url}]
(handler (assoc req :connection db))))))
(defn make-handler [db-url]
(let [wrap-db (make-wrap-db db-url)]
(-> voting
(wrap-db)
(wrap-with-logger))))
(defn -main [& args]
(let [
url (System/getenv "JDBC_DATABASE_URL")
portString (System/getenv "PORT")
port (Integer/parseInt portString)
]
(run-jetty (make-handler url) {:port port})))
I think you are rebinding the db local variable in your defroutes.
(defroutes voting
(POST "/vote" [:as {db :connection}] (vote-for-paper db 1 2)))
Should be
(defroutes voting
(POST "/vote" (vote-for-paper db 1 2)))
Can you give that a try? I’m on mobile so that’s untested code.
I had the same problem and changed my project.clj’s postgresql driver from
[postgresql "9.3-1102.jdbc41"]
to
[org.postgresql/postgresql "42.2.6.jre7"]
and the problem went away.
Related
I'm working on a simple project that shows some data that I'd like to see everyday. This will go on to my raspberry-pi. I'm using a free api that has a limit on requests so I thought I'd cache the requests so I don't spam the API. Here is what I've got so far:
(def KEY "Cache-Key")
(def CF (cache/ttl-cache-factory {} :ttl 43200)) ; 12 hour cache
(defn get-data-from-api
[url]
(let [response {:cache true :value 1}]
(println "---> getting from http")
response))
(defn get-data
[url]
(cache/lookup-or-miss CF KEY (get-data-from-api url)))
According to this link, this is all that is required. Except:
my get-data function always gets it from the api (the println I added to debug gets printed always). The cache is being added just fine, just doesn't seem to fetch and return
The get-data doesn't return anything. So when I do curl http://localhost:3001/display I get an empty response.
Am I using the cache correctly please?
The last value to lookup-or-miss must be a function that will be called on a cache miss. In your code, you're first calling the function and then pass its result to the lookup function, so your function will be called unconditionally (after all, lookup-or-miss is a regular function itself and not a macro - it can't dictate when its arguments are evaluated).
Even in the article you link to, they pass http-get directly and the url serves as the key, which lookup-or-miss will use as an argument for http-get by default on a cache miss.
Suppose I need widget data and widget parts data. I need to retrieve the widget data via http request to get its parts-numbers. I use those parts-numbers to make more http requests to get parts data.
Using https://github.com/Day8/re-frame-http-fx, it'd look like:
(reg-event-fx
:foo/get-widget
(fn [{:keys [db]} [_]]
{:http-xhrio {:method :get
:uri "foobar.com/widget"
:format (ajax/transit-request-format)
:response-format (ajax/json-response-format)
:on-success [:foo/load-widget]
:on-failure [:foo/set-error]}}))
(reg-event-fx
:foo/get-widget-part
(fn [{:keys [db]} [_ part-number]]
{:http-xhrio {:method :get
:uri (str "foobar.com/part/" part-number)
:format (ajax/transit-request-format)
:response-format (ajax/json-response-format)
:on-success [:foo/load-part]
:on-failure [:foo/set-error]}}))
How would I initialize my parts data for my page? The most straightforward method I can come up with is to wrap get-widget and get-widget-part by writing another handler get-widget-then-widget-parts by doing a http request for the widget and on success take that data and retrieve parts data. My issue with that is that it isn't very composable. I need to create another handler. At the same time I can't just (dispatch [:foo/get-widget]) and feed the result into (dispatch [:foo/get-widget-part]) (as far as I know).
If I understand correctly, your aim is to create multiple get-widget-part requests after get-widget returns the widget data with part ids. You could write an event handler that looks up the ids, and dispatches multiple :foo/get-widget-part events.
(reg-event-fx
:foo/load-widget ;Your :on-success event
(fn [{:keys [db]} [_ widget-data]]
(let [ids (get-part-ids widget-data)
missing-ids (remove #(get-part-with-id db %) ids)] ;Load only missing parts
{:db (set-widget-data db widget-data)
:dispatch-n (map (fn [id] [:foo/get-widget-part id]) missing-ids)})))
You likely don't want to fetch the parts "eagerly" every time. So, you could either A) provide a separate argument (e.g., :fetch-eager) and merge the :dispatch-n conditionally depending on that, or B) create separate events for lazy and eager fetching (say, :foo/get-widget and :foo/get-widget-with-parts). I would prefer the latter option B, as it easier to build upon, for example, when a dedicated API endpoint is added for fetching the widget with parts.
You can compose the creation of the effect map returned from the event handler. In the above example, lazy fetch action would create just a :db effect (e.g., mk-db-widget-data), while the eager version would be composed of both the :dbupdate and the :get-widget-part events (e.g., mk-dispatch-get-widget-parts).
I have code that looks something like the below:
(defn on-message [event]
(do-stuff))
(defn build-websocket []
(let [ws (js.window.WebSocket. "ws://localhost:8888/ws/")]
(set! (.-onopen ws) on-open)
(set! (.-onclose ws) on-close)
(set! (.-onerror ws) on-error)
(set! (.-onmessage ws) on-message)
ws))
I'm using figwheel. I have noticed that when I change my callbacks (on-message, on-error, etc), the app does reload, but old versions of these functions still get called.
(defn on-message [event]
; Changed. Requires hard reload to be called on websocket message.
(do-other-stuff))
I understand that this is because the old version of the function is still referenced by the websocket.
Is there a pattern that would make this code reloadable? Perhaps I should be using core/async? If so, what would that look like?
Perhaps your code is not reloadable. Another thing to look at, for quick fix, is to always reload the namespace when you save from your editor/IDE:
(ns ^:figwheel-always my.namespace
(:require [clojure.string :as str])
Notice the ^:figwheel-always metadata.
For more on writing reloadable code see here.
I find that incremental development tends to break when coding for Hunchentoot.
For example, I might write a web page that is composed of a few functions. If one of these inner functions contains a call to - say - hunchentoot:post-parameters* then I can't easily test the function in the REPL. It'll error out because *request* doesn't exist unless the page is called by a web client.
It would be nice if some function-or-other-source existed such that I could test my-function thus:
>(let* ((*request* (get-previous-request-from-somewhere))
(*session* (slot-value *request* 'hunchentoot:session)))
(my-function <whatever params>))
Does it or something similar exist? Am I overlooking a better approach to debugging?
My interim solution looks something like this:
(defparameter *save-last-request* t)
(defvar *last-request* nil)
(defun store-request ()
(when *save-last-request*
(setf *last-request* *request*)))
(defmacro with-last-request (&body body)
`(let* ((*request* *last-request*)
(*session* (slot-value *request* 'hunchentoot:session)))
,#body))
It works fine with the caveat that each handler needs to make a call to store-request.
I think the simplest thing to do might be to use a custom request class that introduces a way to persist requests somewhere into the initializer chain.
Here's a trivial example of one approach. A custom subclass of request which saves it's state, in a global stack.
You can set your acceptors to use custom request-classes using
(setf (acceptor-request-class acceptor ) new-value)
so something like this
(defparameter *requests* nil)
(defclass my-request (hunchentoot:request) ())
(defmethod initialize-instance :after ((req my-request) &key)
(push req *requests*))
and then set the acceptor request class to use this when you make your acceptor e.g.
(setf (hunchentoot:acceptor-request-class
(make-instance 'hunchentoot:easy-acceptor)) 'my-request)
Every time a request is created by this acceptor to pass to the handler, it will be added to the *requests* list.
if you use a variable to specify the request class name you could toggle this class on and off for development/debugging.
You could then take requests from this stack in your test binding.
I have a compojure app that uses the ring session wrapper to store the OAuth token associated with the current user. I would like for this token to remain available when the server restarts, so that I don't have to go through the auth process each time.
I assumed that using the cookie-store instead of the default memory-store would help, but it does not. What am I missing?
This is the relevant part of the code:
(defn auth-callback-handler
[session {code :code}]
(let [token (retrieve-token code)]
(-> (redirect "/") (assoc :session (assoc session :token token)))))
(defroutes app-routes
(GET "/" {session :session} (root-handler session))
(GET "/auth-callback" {session :session params :params} (auth-callback-handler session params))
(route/not-found "Not Found"))
(def app
(-> (handler/site app-routes)
(wrap-session {:store (cookie-store {:key "a 16-byte secret"})})))
The function root-handler uses the token to decide if someone is logged in or not, but does not return anything in the way of session info.
The issue is that you have 2 wrap-session middlewares in your app, as the handler/site comes with one. This is causing the encrypt/decrypt to be run twice. To configure the compojure session handle use:
(def app
(site app-routes {:session {:store (cookie-store {:key "a 16-byte secret"})}}))
Also, perhaps you would be interested on some of these projects, which implement the ring SessionStore protocol:
https://github.com/sritchie/couch-session
https://github.com/wuzhe/clj-redis-session
https://github.com/rmarianski/servlet-session-store
To make the last one persistent you will need to check the documentation of your servlet container of choice.