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

View file

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

View file

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