That's nice. We could do something like:

(-> (swap! ...)
  force
  :access_token)

On Mon, Jun 15, 2020 at 7:57 PM Justin Smith <noisesm...@gmail.com> wrote:

> The usage of delay here is clever. I suggest as an addition, using
> `force` instead of `deref` to disambiguate delay vs. atom (of course
> if you take a few moments to think about it, swap! shouldn't return an
> atom etc., but I think it becomes clearer with force).
>
> On Mon, Jun 15, 2020 at 10:34 AM Ernesto Garcia <titogar...@gmail.com>
> wrote:
> >
> > Hi, it's a long time that this question was posted, but I have found it
> interesting in the implementation of token refreshes.
> >
> > First of all, for service invocation, given a `revise-oauth-token`
> method, I think this is good client code:
> >
> > (http/request
> >   {:method :get
> >    :url "https://example.com/";
> >    :oauth-token (revise-oauth-token token-store)})
> >
> > If you find it too repetitive or fragile in your client code, you can
> make a local function, but I wouldn't abstract the service invocation at a
> higher layer.
> >
> > Regarding the implementation of the token store, we could initially
> think of a synchronized store, like an atom, and `revise-oauth-token` would
> swap its content when a refresh is required. This is inconvenient for
> multithreaded clients, because there could be several refresh invocations
> going on concurrently.
> >
> > In order to avoid concurrent refreshes, I propose to implement the token
> store as an atom of promises. Implementation of `revise-oauth-token` would
> be:
> >
> > (defn revise-oauth-token [token-store]
> >   (:access_token
> >     @(swap! token-store
> >        (fn [token-promise]
> >          (if (token-needs-refresh? @token-promise (Instant/now))
> >            (delay (refresh-oauth-token (:refresh_token @token-promise)))
> >            token-promise)))))
> >
> > Note that using a delay avoids running `refresh-oauth-token` within the
> `swap!` operation, as this operation may be run multiple times.
> > Also note that `token-needs-refresh` takes an argument with the present
> time. This keeps the function pure, which could help for unit testing, for
> example.
> >
> > There is an alternative implementation using `compare-and-set!` that
> avoids checking `token-needs-refresh?` several times, but it is more
> complicated. I have posted full sample code in a gist:
> https://gist.github.com/titogarcia/4f09bcc5fa38fbdc1076954b9a99a8fc
> >
> > Remark: None of this refers to "functional programming" per se. Dealing
> with state in a purely functional way involves using different constructs
> (like possibly monads, for which you can find Clojure libraries if you are
> interested), and best practices are still a topic of research. Clojure has
> taken the pragmatic approach of making purely functional code easy to
> write, but it doesn't reject the use of state, rather it provides
> well-behaved primitives like vars, atoms, agents, etc.
> >
> > Ernesto
> >
> > --
> > You received this message because you are subscribed to the Google
> > Groups "Clojure" group.
> > To post to this group, send email to clojure@googlegroups.com
> > Note that posts from new members are moderated - please be patient with
> your first post.
> > To unsubscribe from this group, send email to
> > clojure+unsubscr...@googlegroups.com
> > For more options, visit this group at
> > http://groups.google.com/group/clojure?hl=en
> > ---
> > You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> > To unsubscribe from this group and stop receiving emails from it, send
> an email to clojure+unsubscr...@googlegroups.com.
> > To view this discussion on the web visit
> https://groups.google.com/d/msgid/clojure/ac79058b-2c31-4b9c-9cf3-e2de998eb8deo%40googlegroups.com
> .
>
> --
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clojure@googlegroups.com
> Note that posts from new members are moderated - please be patient with
> your first post.
> To unsubscribe from this group, send email to
> clojure+unsubscr...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en
> ---
> You received this message because you are subscribed to a topic in the
> Google Groups "Clojure" group.
> To unsubscribe from this topic, visit
> https://groups.google.com/d/topic/clojure/Vur5Lol45EE/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to
> clojure+unsubscr...@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/clojure/CAGokn9L_Od2ZN2LJAsYUfJ2G_hbLKkamkUxgFX2vTKySxpHQWg%40mail.gmail.com
> .
>

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/clojure/CAH%2Be2UzLSskmCs%3Dm2TO%2BRhhgmX%2BcO%2BHoXAO8WFjdLxzMyORJUA%40mail.gmail.com.

Reply via email to