Skip to content

GH-3805: Change to select between spinLock and pub-sub for the lock method #3819

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from

Conversation

Meteorkor
Copy link
Contributor

Resolves #3805

It has been changed so that the user can choose between the spinLock method and the pub-sub method.

In the default, spinLock is set as the default so that there is no problem in the past version.

Change RedisLock to abstract class and leave common parts
Separated into RedisSpinLock and RedisPubSubLock for each specialized part.

Any comments are always welcome.
thank you

Copy link
Member

@artembilan artembilan left a comment

Choose a reason for hiding this comment

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

This is all great, but need some clarification.

Plus it would be great to add some documentation note with reasoning and links to reliable sources.

Thanks

@@ -226,12 +200,27 @@ public void setCacheCapacity(int cacheCapacity) {
this.cacheCapacity = cacheCapacity;
}

/**
* The default is {@link RedisLockType.SPIN_LOCK}<br>
Copy link
Member

Choose a reason for hiding this comment

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

Please, consider do not use <br> in JavaDocs.
Better to provide a <p> for a new paragraph.

I believe this method better to provide more info as "why?", what is the premise of such a decision?
Therefore end-user would know that in some cases the pub-sub won't work.

* Select the lock method.
*
* @param redisLockType obtain RedisLockType
* @since 6.0.0
Copy link
Member

Choose a reason for hiding this comment

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

We have to back-port the fix into 5.5.x, therefore @since 5.5.13

* @since 6.0.0
*/
public void setRedisLockType(@Nonnull RedisLockType redisLockType) {
this.redisLockType = Objects.requireNonNull(redisLockType);
Copy link
Member

Choose a reason for hiding this comment

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

We prefer to use our own API: org.springframework.util.Assert.notNull(@Nullable Object object, String message).
However I don't think this method will need anything when we switch to plain boolean...

PUB_SUB_LOCK, SPIN_LOCK;
}

private Function<String, RedisLock> getRedisLockConstructor(@Nonnull RedisLockType redisLockType) {
Copy link
Member

Choose a reason for hiding this comment

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

We prefer our own org.springframework.lang.NonNull.
See its JavaDocs for a reason.

Although with the plain boolean flag I don't think we need any annotation at all....

"return false";
private final RedisScript<Boolean> obtainLockScript = new DefaultRedisScript<>(OBTAIN_LOCK_SCRIPT, Boolean.class);
private final RedisScript<Boolean> unLinkUnLockScript = new DefaultRedisScript<>(UNLINK_UNLOCK_SCRIPT, Boolean.class);
private final RedisScript<Boolean> deleteUnLockScript = new DefaultRedisScript<>(DELETE_UNLOCK_SCRIPT, Boolean.class);
Copy link
Member

Choose a reason for hiding this comment

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

It is better to have every class member to be separated with blank lines: much easier to read the code.

From here I even wonder if we need those constants for script texts.

Plus it looks like these RedisScript properties could be just static

" return true\n" +
"end\n" +
"return false";
private final RedisScript<Boolean> obtainLockScript = new DefaultRedisScript<>(OBTAIN_LOCK_SCRIPT, Boolean.class);
Copy link
Member

Choose a reason for hiding this comment

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

Isn't this property the same what we have in the RedisPubSubLock?
Cannot this go to the super class?

RedisLockRegistry.this.redisTemplate.delete(this.lockKey);
}

private boolean obtainLock() {
Copy link
Member

Choose a reason for hiding this comment

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

Isn't this method the same as in the RedisPubSubLock?
Cannot it go to the super class, too?

@@ -779,5 +832,4 @@ private void waitForExpire(String key) throws Exception {
private static Map<String, Lock> getRedisLockRegistryLocks(RedisLockRegistry registry) {
return TestUtils.getPropertyValue(registry, "locks", Map.class);
}

Copy link
Member

Choose a reason for hiding this comment

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

As I said before: our preferences (for better code readability) is to have every single class member (even the last method) to be wrapped with blank lines: https://github.com/spring-projects/spring-integration/wiki/Spring-Integration-Framework-Code-Style#blank-lines

@Meteorkor Meteorkor requested a review from artembilan June 6, 2022 23:25
Copy link
Member

@artembilan artembilan left a comment

Choose a reason for hiding this comment

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

I'm asking about docs one more time 😄

Thanks

private Function<String, RedisLock> getRedisLockConstructor(@NonNull RedisLockType redisLockType) {
return switch (redisLockType) {
case PUB_SUB_LOCK -> RedisPubSubLock::new;
case SPIN_LOCK -> RedisSpinLock::new;
Copy link
Member

Choose a reason for hiding this comment

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

We cannot use switch expression because we have to back-port to 5.5.x which is still based on Java 8.

* @param redisLockType obtain RedisLockType
* @since 5.5.13
*/
public void setRedisLockType(@NonNull RedisLockType redisLockType) {
Copy link
Member

Choose a reason for hiding this comment

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

We assume that everything is not null, unless it is marked as @Nullable.
So, we typically don't use this annotation at all, unless we declare a @NonNullApi in the package-info.java.
Then we need to revise all the public API to honor nullability contract, so Kotlin projects won't fail.

Since there is only this RedisLockRegistry in this org.springframework.integration.redis.util, i won't mind if you address this concern in this PR as well.

@@ -260,9 +258,34 @@ public void destroy() {
}
}

private final class RedisLock implements Lock {
public enum RedisLockType {
PUB_SUB_LOCK, SPIN_LOCK;
Copy link
Member

Choose a reason for hiding this comment

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

These constants have to have JavaDocs: they are public API.

"end " +
"return false";

private static final RedisScript<Boolean> unLinkUnLockScript = new DefaultRedisScript<>(UNLINK_UNLOCK_SCRIPT, Boolean.class);
Copy link
Member

Choose a reason for hiding this comment

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

If it is static final, then it is a constant and therefore has to be declared only in capital letters.

}

/**
* Used by RedisPubSubLock
*/
private static final class RedisUnLockNotifyMessageListener implements MessageListener {
Copy link
Member

Choose a reason for hiding this comment

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

This is private class - cannot it move into RedisPubSubLock class directly to preserve a context?

@Meteorkor Meteorkor requested a review from artembilan June 7, 2022 22:37
Copy link
Member

@artembilan artembilan left a comment

Choose a reason for hiding this comment

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

I'd like to merge this, but there is need some documentation note to be added into redis.adoc in the [[redis-lock-registry]] section.

Let me know if you add it or you want me to do that for you!

Thank you.


private final String lockKey;
private Function<String, RedisLock> getRedisLockConstructor(@NonNull RedisLockType redisLockType) {
Copy link
Member

Choose a reason for hiding this comment

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

Remove, please, this @NonNull as we discussed before.

@artembilan
Copy link
Member

Hi, @Meteorkor !

Thank you for prompt updates to the PR.

Let me know if you see my additional requests for docs like this:

I'd like to merge this, but there is need some documentation note to be added into redis.adoc in the [[redis-lock-registry]] section.

@Meteorkor
Copy link
Contributor Author

Meteorkor commented Jun 8, 2022

redis.adoc

@artembilan
Oh thanks, could you please update it for me?

Thank you.

Copy link
Member

@artembilan artembilan left a comment

Choose a reason for hiding this comment

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

Pulling this locally for final review and docs.

I will fix Checkstyle violation on merge:

Error: eckstyle] [ERROR] /home/runner/work/spring-integration/spring-integration/spring-integration-redis/src/main/java/org/springframework/integration/redis/util/RedisLockRegistry.java:54:8: Unused import - org.springframework.lang.NonNull. [UnusedImports]

@artembilan
Copy link
Member

Merged as cf6ce96 and cherry-picked to 5.5.x

@artembilan artembilan closed this Jun 8, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Connection failures and application hangs with RedisLockRegistry since Spring Boot upgrade
2 participants