Skip to content

Instantly share code, notes, and snippets.

@transducer
Created November 6, 2023 15:13
Show Gist options
  • Save transducer/7bb822bd3ab573301daf794b6a983bc6 to your computer and use it in GitHub Desktop.
Save transducer/7bb822bd3ab573301daf794b6a983bc6 to your computer and use it in GitHub Desktop.
Custom RESTEasy client for Keycloak in Clojure
(ns custom-resteasy-client
"Creates a custom `javax.ws.rs.client.Client` with settings for timeouts,
evicting idle connections and a retry handler. This client can be a
resteasyClient for KeycloakBuilder that does not lead to \"RESTEASY004655
Unable to invoke request: java.net.SocketException: Connection reset errors\"
according to the suggestion in
https://github.com/keycloak/keycloak/issues/8917#issuecomment-1712895984."
(:import
(java.util.concurrent TimeUnit)
(org.apache.http.impl.client DefaultHttpRequestRetryHandler HttpClients)
(org.apache.http.impl.conn PoolingHttpClientConnectionManager)
(org.jboss.resteasy.client.jaxrs ResteasyClientBuilder)
(org.jboss.resteasy.client.jaxrs.engines ApacheHttpClient43Engine)))
(defn- build-http-client []
(let [cm (doto (PoolingHttpClientConnectionManager.)
(.setValidateAfterInactivity 1000)
(.setMaxTotal 200)
(.setDefaultMaxPerRoute 20))]
(.. (HttpClients/custom)
(setConnectionManager cm)
evictExpiredConnections
(evictIdleConnections 10000 TimeUnit/MILLISECONDS)
(setRetryHandler DefaultHttpRequestRetryHandler/INSTANCE)
build)))
(defn build
"Creates a custom `javax.ws.rs.client.Client` with settings for timeouts,
evicting idle connections and a retry handler"
[]
(let [http-client (build-http-client)
engine (ApacheHttpClient43Engine. http-client)]
(.. (ResteasyClientBuilder/newBuilder)
(httpEngine engine)
(connectTimeout 10000 TimeUnit/MILLISECONDS)
(readTimeout 7000 TimeUnit/MILLISECONDS)
(connectionTTL -1 TimeUnit/MILLISECONDS)
disableTrustManager
build)))
(ns keycloak
(:require
[clojure.tools.logging :as log]
[custom-resteasy-client :as custom-resteasy-client]
[integrant.core :as ig])
(:import
(org.keycloak OAuth2Constants)
(org.keycloak.admin.client KeycloakBuilder)))
(defn create-keycloak-client-realm
[realm server-url client-id client-secret username user-password]
(.. KeycloakBuilder
builder
(serverUrl server-url)
(realm realm)
(grantType OAuth2Constants/PASSWORD)
(clientId client-id)
(clientSecret client-secret)
(username username)
(password user-password)
(resteasyClient (custom-resteasy-client/build))
build
(realm realm)))
@johann-oikonomou
Copy link

Hi!
Awesome piece of work 👍
Did you tune the settings/timeouts to your needs or are they the default ones keycloak would use?

@transducer
Copy link
Author

@johann-oikonomou this gist is a translation of someone else's java code to clojure on the GitHub issue about the socket timeouts mentioned in the comment. The settings and timeouts are sensible defaults. Note that in our case it did not solve all socket exceptions, but reduced them by a factor 10.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment