Question (or idea?) about wrap-session

31 views
Skip to first unread message

Don Jackson

unread,
Aug 4, 2011, 2:34:48 AM8/4/11
to ring-c...@googlegroups.com

For a web app I am developing, there are some things I need to compute for a user that take "a long time", e.g. many seconds.

If I begin these computations as a direct result of a user request, the user will need to wait for the response, and I'd prefer to do better, if possible.

To the extent that I can avoid needing the result(s) of those lengthy computations for the first page(s) the user accesses, it seems like it would behoove me
to begin these long tasks in the background (via a Clojure future?), upon first access. It may very well take the user several seconds (or longer) to get
to the part of the app that needs these results, and if I'm lucky, they will already be done when the user needs them, or worst case, at least I got a head start on this
computation, and now the user will just need to wait a bit longer for it to finish.

So, I'm thinking I'd like to store the results of all this "eager" computation in the user's session.

Ring's wrap-session (and Sandbar's wrap-stateful-session) look pretty useful for all this.

My question: Is there a way to provide a (callback) function to wrap-session that would get executed when a new session is created?
If so, how?

If not, might this be a good addition to wrap-session?

Perhaps a new option :new-session-callback whose value is obviously the function to be called.
Presumably the callback function would be provided access to the newly created session, so it can read and update it.

Is this a decent, or terrible idea? :-)

If not so bad, where best to call the provided callback function?

Advice, pointers, feedback welcome.

Don

Daniel Werner

unread,
Aug 7, 2011, 1:49:55 PM8/7/11
to Ring
Hello Don,

On Aug 4, 8:34 am, Don Jackson <r...@clark-communications.com> wrote:
> For a web app I am developing, there are some things I need to compute for a user that take "a long time", e.g. many seconds.
>
> If I begin these computations as a direct result of a user request, the user will need to wait for the response,  and I'd prefer to do
> better, if possible. [...] So, I'm thinking I'd like to store the results of all this "eager" computation in the user's session.

Depending on the kind data you'd like to store, perhaps you could use
memoization to your avail, without messing with sessions at all. This
way, if the data is user-agnostic, you might be able to serve the same
results to multiple clients. I've heard good things about the cache-
dot-clj library, which apparently has been continued as clj-cache:

https://github.com/bmabey/clj-cache

As you already mentioned, your memoized functions could return
futures, thereby asynchronously moving the work into the futures
+agents threadpool.

Hope that helps,
--
Daniel

Don Jackson

unread,
Aug 9, 2011, 7:16:57 PM8/9/11
to ring-c...@googlegroups.com

On Aug 7, 2011, at 10:49 AM, Daniel Werner wrote:

> Hello Don,
>
> On Aug 4, 8:34 am, Don Jackson <r...@clark-communications.com> wrote:
>> For a web app I am developing, there are some things I need to compute for a user that take "a long time", e.g. many seconds.
>>
>> If I begin these computations as a direct result of a user request, the user will need to wait for the response, and I'd prefer to do
>> better, if possible. [...] So, I'm thinking I'd like to store the results of all this "eager" computation in the user's session.
>
> Depending on the kind data you'd like to store, perhaps you could use
> memoization to your avail, without messing with sessions at all. This
> way, if the data is user-agnostic, you might be able to serve the same
> results to multiple clients.

I've considered that, but for the most part, the results of these computations/results are completely user-specific.
Seems like one advantage of keeping this info in the session might be that it would be "easier" to know when it was no longer needed…..
(same decision as session…)

The other concern is that I would prefer to begin these user-specifc computations as early as possible when the user first touches the web application.
I'd prefer to not have to call the function that required the result at the instant that I need the result. I'd like to try and have all these results available before the
user requests them thru the browser UI. And I'd prefer not to have to stick a "check if all the user stuff has been computed, if not start" into every URL path into my app
(but clearly I could do that centrally before I dispatch to the specific function that implements that URL…)

I do understand that a user is not identical to a session, the same user could possible have more than one simultaneous session (different browsers, mobile vs desktop, etc), but optimizing that seems
pretty low payoff to me right now…..

I'm looking for some specific advice about where in the wrap-sessions code is a new session created/stored.

https://github.com/mmcgrana/ring/blob/master/ring-core/src/ring/middleware/session.clj

Once I understand that, presumably I can figure out how to hack in a callback…..

Don

rapala

unread,
Aug 10, 2011, 4:38:51 PM8/10/11
to Ring
On 10 elo, 02:16, Don Jackson <r...@clark-communications.com> wrote:
> I've considered that, but for the most part, the results of these computations/results are completely user-specific.
> Seems like one advantage of keeping this info in the session might be that it would be "easier" to know when it was no longer needed…..
> (same decision as session…)

How time sensitive these results are? User might first visit the site
and start the computation, take a 10 minute break and then visit the
"show the results" page. Would the results still be valid? I would
implement a keep-alive system for the results. Every request to the
site refreshes the result or starts the computation. If there are no
request for n seconds/minutes/hours then the result is deleted.

> The other concern is that I would prefer to begin these user-specifc computations as early as possible when the user first touches the web application.
> I'd prefer to not have to call the function that required the result at the instant that I need the result.  I'd like to try and have all these results available before the
> user requests them thru the browser UI.   And I'd prefer not to have to stick a "check if all the user stuff has been computed, if not start" into every URL path into my app
> (but clearly I could do that centrally before I dispatch to the specific function that implements that URL…)

The idea above could be implemented with a middleware. It would
identify the user and refresh the result. Something like:
(defn wrap-results [handler]
(fn [req]
(let [user (identify-user req)
result (get-result user)]
(if (result-stale? result)
(compute-new-result))
(handler req))))

> I'm looking for some specific advice about where in the wrap-sessions code is a new session created/stored.  
>
>        https://github.com/mmcgrana/ring/blob/master/ring-core/src/ring/middl...
>
> Once I understand that, presumably I can figure out how to hack in a callback…..

It seems that the new session is "created" by (read-session store sess-
key) when no sess-key exists in the cookie and a nil is passed
instead. In this case the :session key in the request map will be
associated with an empty map. But you should take this with a grain of
salt.

// Jani
Reply all
Reply to author
Forward
0 new messages