Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ public byte[] serialize(Object t) {
boolean allValuesAreClientDTOs = true;
for (final LoginSource loginSource : LoginSource.oauthSources) {
final Object value = data.get(loginSource.name().toLowerCase());
if (value != null && !(value instanceof OAuth2AuthorizedClientDTO)) {
if (value != null && !(value instanceof OAuth2AuthorizedClient)) {
allValuesAreClientDTOs = false;
break;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.appsmith.server.migrations.db.ce;

import io.mongock.api.annotations.ChangeUnit;
import io.mongock.api.annotations.Execution;
import io.mongock.api.annotations.RollbackExecution;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.ReactiveRedisOperations;
import org.springframework.data.redis.core.script.RedisScript;
import reactor.core.publisher.Flux;

@RequiredArgsConstructor
@Slf4j
@ChangeUnit(order = "063", id = "reset_session_oauth2_spring_3_3")
public class Migration063CacheBustSpringBoot3_3 {

private final ReactiveRedisOperations<String, String> reactiveRedisOperations;

@RollbackExecution
public void rollbackExecution() {}

@Execution
public void execute() {
doClearRedisOAuth2AuthClientKeys(reactiveRedisOperations);
}
Comment on lines +23 to +25
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add exception handling in the execute method

It's good practice to handle exceptions to make your code more robust. In the execute() method, consider adding a try-catch block to catch any exceptions that may occur during the Redis operations. This way, you can log the error and handle it appropriately.

public void execute() {
    try {
        doClearRedisOAuth2AuthClientKeys(reactiveRedisOperations);
    } catch (Exception e) {
        log.error("An error occurred while clearing OAuth2 client keys from Redis", e);
        // Optionally, handle the exception or rethrow it
    }
}


public static void doClearRedisOAuth2AuthClientKeys(
ReactiveRedisOperations<String, String> reactiveRedisOperations) {
final String authorizedClientsKey =
"sessionAttr:org.springframework.security.oauth2.client.web.server.WebSessionServerOAuth2AuthorizedClientRepository.AUTHORIZED_CLIENTS";
final String script =
"for _,k in ipairs(redis.call('keys','spring:session:sessions:*')) do local fieldExists = redis.call('hexists', k, '"
+ authorizedClientsKey + "'); if fieldExists == 1 then redis.call('del', k) end end";
Comment on lines +31 to +33
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Avoid using KEYS command in Redis scripts

Remember that using the KEYS command in Redis can be problematic in production environments. It can block the Redis server if there are many keys, leading to performance issues.

Instead, consider using the SCAN command, which is non-blocking and more suitable for iterating over keys in a large keyspace. Here's an example of how you can modify the script:

final String script =
    "local cursor = '0' " +
    "repeat " +
    "  local result = redis.call('SCAN', cursor, 'MATCH', 'spring:session:sessions:*') " +
    "  cursor = result[1] " +
    "  local keys = result[2] " +
    "  for _,k in ipairs(keys) do " +
    "    local fieldExists = redis.call('hexists', k, '" + authorizedClientsKey + "') " +
    "    if fieldExists == 1 then " +
    "      redis.call('del', k) " +
    "    end " +
    "  end " +
    "until cursor == '0'";

final Flux<Object> flushdb = reactiveRedisOperations.execute(RedisScript.of(script));

flushdb.blockLast();
}
Comment on lines +27 to +37
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Avoid blocking calls in reactive streams

Dear student, it's important to remember that using blocking calls like blockLast() in a reactive pipeline can undermine the benefits of reactive programming. Blocking operations can lead to performance bottlenecks and thread starvation.

To maintain a non-blocking, asynchronous flow, consider refactoring the code to use reactive operators and subscribing to the sequence without blocking. Here's how you might modify the code:

reactiveRedisOperations.execute(RedisScript.of(script))
    .doOnError(error -> log.error("Error executing Redis script", error))
    .doOnComplete(() -> log.info("Successfully cleared OAuth2 client keys from Redis"))
    .subscribe();

}