On Mon, Jun 15, 2020 at 7:34 PM 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
>

I think it is worth mentioning an alternative approach to avoid concurrent
token refresh may be to use a scheduled task to run shortly before the
currently valid token is going to expire.
The http call then only needs deref and the background task can even use
reset! on the atom, as there are no concurrent update operations to race
against.

--
Alex

-- 
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/CACACo5TMJPt8CNbk0DS2z%3D%2BVsnadMNRH%3DdPPX%3DBGePWkdRBYXg%40mail.gmail.com.

Reply via email to