Use retry-logic only for the map storage

This is a performance optimization that the retry doesn't affect the legacy store.

Closes #20176
This commit is contained in:
Alexander Schwartz 2023-05-05 13:42:00 +02:00 committed by Michal Hajas
parent 754aac2f4e
commit bd7f62acc3
3 changed files with 47 additions and 32 deletions

View file

@ -20,6 +20,7 @@ package org.keycloak.protocol.oidc.endpoints;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.keycloak.OAuth2Constants; import org.keycloak.OAuth2Constants;
import org.keycloak.authentication.AuthenticationProcessor; import org.keycloak.authentication.AuthenticationProcessor;
import org.keycloak.common.Profile;
import org.keycloak.common.util.ResponseSessionTask; import org.keycloak.common.util.ResponseSessionTask;
import org.keycloak.constants.AdapterConstants; import org.keycloak.constants.AdapterConstants;
import org.keycloak.events.Details; import org.keycloak.events.Details;
@ -129,16 +130,21 @@ public class AuthorizationEndpoint extends AuthorizationEndpointBase {
* Process the request in a retriable transaction. * Process the request in a retriable transaction.
*/ */
private Response processInRetriableTransaction(final MultivaluedMap<String, String> formParameters) { private Response processInRetriableTransaction(final MultivaluedMap<String, String> formParameters) {
return KeycloakModelUtils.runJobInRetriableTransaction(session.getKeycloakSessionFactory(), new ResponseSessionTask(session) { if (Profile.isFeatureEnabled(Profile.Feature.MAP_STORAGE)) {
@Override return KeycloakModelUtils.runJobInRetriableTransaction(session.getKeycloakSessionFactory(), new ResponseSessionTask(session) {
public Response runInternal(KeycloakSession session) { @Override
session.getContext().getHttpResponse().setWriteCookiesOnTransactionComplete(); public Response runInternal(KeycloakSession session) {
// create another instance of the endpoint to isolate each run. session.getContext().getHttpResponse().setWriteCookiesOnTransactionComplete();
AuthorizationEndpoint other = new AuthorizationEndpoint(session, // create another instance of the endpoint to isolate each run.
new EventBuilder(session.getContext().getRealm(), session, clientConnection), action); AuthorizationEndpoint other = new AuthorizationEndpoint(session,
// process the request in the created instance. new EventBuilder(session.getContext().getRealm(), session, clientConnection), action);
return other.process(formParameters); } // process the request in the created instance.
}, 10, 100); return other.process(formParameters);
}
}, 10, 100);
} else {
return process(formParameters);
}
} }
private Response process(MultivaluedMap<String, String> params) { private Response process(MultivaluedMap<String, String> params) {

View file

@ -173,18 +173,22 @@ public class TokenEndpoint {
@Consumes(MediaType.APPLICATION_FORM_URLENCODED) @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@POST @POST
public Response processGrantRequest() { public Response processGrantRequest() {
// grant request needs to be run in a retriable transaction as concurrent execution of this action can lead to if (Profile.isFeatureEnabled(Profile.Feature.MAP_STORAGE)) {
// exceptions on DBs with SERIALIZABLE isolation level. // grant request needs to be run in a retriable transaction as concurrent execution of this action can lead to
return KeycloakModelUtils.runJobInRetriableTransaction(session.getKeycloakSessionFactory(), new ResponseSessionTask(session) { // exceptions on DBs with SERIALIZABLE isolation level.
@Override return KeycloakModelUtils.runJobInRetriableTransaction(session.getKeycloakSessionFactory(), new ResponseSessionTask(session) {
public Response runInternal(KeycloakSession session) { @Override
// create another instance of the endpoint to isolate each run. public Response runInternal(KeycloakSession session) {
TokenEndpoint other = new TokenEndpoint(session, new TokenManager(), // create another instance of the endpoint to isolate each run.
new EventBuilder(session.getContext().getRealm(), session, clientConnection)); TokenEndpoint other = new TokenEndpoint(session, new TokenManager(),
// process the request in the created instance. new EventBuilder(session.getContext().getRealm(), session, clientConnection));
return other.processGrantRequestInternal(); // process the request in the created instance.
} return other.processGrantRequestInternal();
}, 10, 100); }
}, 10, 100);
} else {
return processGrantRequestInternal();
}
} }
private Response processGrantRequestInternal() { private Response processGrantRequestInternal() {

View file

@ -17,6 +17,7 @@
package org.keycloak.services.resources; package org.keycloak.services.resources;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.keycloak.common.Profile;
import org.keycloak.common.util.ResponseSessionTask; import org.keycloak.common.util.ResponseSessionTask;
import org.keycloak.http.HttpRequest; import org.keycloak.http.HttpRequest;
import org.keycloak.OAuth2Constants; import org.keycloak.OAuth2Constants;
@ -256,16 +257,20 @@ public class LoginActionsService {
@QueryParam(Constants.EXECUTION) String execution, @QueryParam(Constants.EXECUTION) String execution,
@QueryParam(Constants.CLIENT_ID) String clientId, @QueryParam(Constants.CLIENT_ID) String clientId,
@QueryParam(Constants.TAB_ID) String tabId) { @QueryParam(Constants.TAB_ID) String tabId) {
return KeycloakModelUtils.runJobInRetriableTransaction(session.getKeycloakSessionFactory(), new ResponseSessionTask(session) { if (Profile.isFeatureEnabled(Profile.Feature.MAP_STORAGE)) {
@Override return KeycloakModelUtils.runJobInRetriableTransaction(session.getKeycloakSessionFactory(), new ResponseSessionTask(session) {
public Response runInternal(KeycloakSession session) { @Override
// create another instance of the endpoint to isolate each run. public Response runInternal(KeycloakSession session) {
session.getContext().getHttpResponse().setWriteCookiesOnTransactionComplete(); // create another instance of the endpoint to isolate each run.
LoginActionsService other = new LoginActionsService(session, new EventBuilder(session.getContext().getRealm(), session, clientConnection)); session.getContext().getHttpResponse().setWriteCookiesOnTransactionComplete();
// process the request in the created instance. LoginActionsService other = new LoginActionsService(session, new EventBuilder(session.getContext().getRealm(), session, clientConnection));
return other.authenticateInternal(authSessionId, code, execution, clientId, tabId); // process the request in the created instance.
} return other.authenticateInternal(authSessionId, code, execution, clientId, tabId);
}, 10, 100); }
}, 10, 100);
} else {
return authenticateInternal(authSessionId, code, execution, clientId, tabId);
}
} }