I have found multiple references to the property --spi-user-storage-provider-timeout but I cannot find any documentation around it. Additionally, including it in my startup appears to have no effect as I still see custom user storage provider SPI calls timing out at 3000ms from time to time.
I was wondering if there is any information out there on configuring this timeout. It appears both client and roles have a similar timeout to the UserStorageManager, but the scope of their config object differs (user, role, client).
The source code indicates that the value should be configurable. I would appreciate any insight into how to do so.
Which provider are you using? Or did you write a custom provider? These props become available to the provider factory so if it’s a custom provider you’ll need to get and use that prop in code to apply a timeout.
I am using a custom user storage provider. However, it appears the issue I am seeing is due to the “wrapping” of provider calls in a timeout by the UserStorageManager class, which is an implementation of the AbstractStorageManager. This class has a default value for the timeout:
/**
* Timeouts are used as time boundary for obtaining models from an external storage. Default value is set
* to 3000 milliseconds and it's configurable.
*/
private static final Long STORAGE_PROVIDER_DEFAULT_TIMEOUT = 3000L;
But mentions it is configurable. I however, have been unable to figure out the correct way to config this timeout in this class, as it does not appear to be an spi or provider, which the documentation makes a bit clearer on how to send properties in for.
I agree that it no longer appears the property I mentioned is working nor does it appear it has ever appeared in documentation, leading to my confusion.
Additionally, in that abstract manager class the constructor sets the scope of the config to “user”
public UserStorageManager(KeycloakSession session) {
super(session, UserStorageProviderFactory.class, UserStorageProvider.class,
UserStorageProviderModel::new, "user");
}
which appears to ultimately mean that the configuration of that class will come from the SystemPropertyConfigProvider and look for configuration from system properties of the form: keycloak.user.* in this case storageProviderTimeout. Below you can see how the Abstract manager fetches that timeout from the Config.scope object with configScope=“user”.
protected Long getStorageProviderTimeout() {
if (storageProviderTimeout == null) {
storageProviderTimeout = Config.scope(configScope).getLong("storageProviderTimeout", STORAGE_PROVIDER_DEFAULT_TIMEOUT);
}
return storageProviderTimeout;
}
I would LOVE to understand how to correctly set this system property
I have tried setting the the storage provider timeout via that manner but I always see it appear in the exception as 3000ms so it does not appear to be honored.
We leverage keycloak as a container so my startup is as part of a compose. The start command contains various args like so:
so it actually does look like the property works. Took a while to get a test to prove it as apparently only getUserById and getUserByUsername are subject to this timeout. I was mapping users via a certificate common name which was an attribute. FWIW this seems to only pop up when I use the common name attribute to kick off a get by the username via:
// This will do a provider get user by username and should leverage KC cache if user is present:
user = this.itsSession.users().getUserByUsername(realmModel, username);
such that the attribute based search will benefit from the KC cache if the user exists already. This path appears to be subject to the timeout but getUserByUsername directly is either called less often in our typical use case or is not experiencing the timeout as often. I will say I do wish there was some logging of the retrieved configuration to know it is being seen as expected.