Skip to content

Potential race condition in listener adding code #2755

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
o-l-o opened this issue Oct 23, 2023 · 2 comments
Closed

Potential race condition in listener adding code #2755

o-l-o opened this issue Oct 23, 2023 · 2 comments
Assignees
Labels
in:messaging Redis messaging components type: bug A general bug

Comments

@o-l-o
Copy link

o-l-o commented Oct 23, 2023

I'm pretty sure that there is potential race condition in the following code:

               Set<Topic> set = listenerTopics.get(listener);

		if (set == null) {
			set = new CopyOnWriteArraySet<>();
			listenerTopics.put(listener, set);
		}

The solution could be to replace it with something like this:

Set<Topic> set = listenerTopics.computeIfAbsent(listener, $ -> new CopyOnWriteArraySet<>());

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Oct 23, 2023
@jxblum
Copy link
Contributor

jxblum commented Oct 23, 2023

Yes! Good find.

Any compound action (i.e. the Map get(:MessageListener), followed by a put(:MessageListener, :Set<Topic>), and then addAll(:Collection<Topic>)) is going to necessarily have possible race conditions if the affected area of code is 1) accessed by multiple Threads and 2) is not properly guarded by a lock, even if the underlying data structure(s) (Map & Set) are Thread-safe, which in this case, they are (a ConcurrentHashMap here and CopyOnWriteArraySet here).

Given 1) the Javadoc on the RedisMessageListenerContainer states the addMessageListener(..) method can be called concurrently without external synchronization, and 2) the addMessageListener(..) method calls the private addListener(..) method, then I'd say the code in question has race conditions.

@jxblum jxblum self-assigned this Oct 23, 2023
@jxblum jxblum added type: bug A general bug in:messaging Redis messaging components and removed status: waiting-for-triage An issue we've not yet triaged labels Oct 23, 2023
@jxblum jxblum closed this as completed in f28bf61 Oct 23, 2023
jxblum added a commit to jxblum/spring-data-redis that referenced this issue Oct 23, 2023
Given addListener(:MessageListener, :Collection<Topic>) could be called concurrently from the addMessageListener(:MessageListener, Collection<Topic>) method by multiple Threads, and the RedisMessageListenerContainer Javadoc specifically states that it is safe to call the addMessageListener(..) method conurrently without any external synchronization, and the registeration (or mapping) of listener to Topics is a componund action, then a race condition is possible.

Closes spring-projects#2755
jxblum added a commit to jxblum/spring-data-redis that referenced this issue Oct 23, 2023
Given addListener(:MessageListener, :Collection<Topic>) could be called concurrently from the addMessageListener(:MessageListener, Collection<Topic>) method by multiple Threads, and the RedisMessageListenerContainer Javadoc specifically states that it is safe to call the addMessageListener(..) method conurrently without any external synchronization, and the registeration (or mapping) of listener to Topics is a componund action, then a race condition is possible.

Closes spring-projects#2755
jxblum added a commit to jxblum/spring-data-redis that referenced this issue Oct 23, 2023
Given addListener(:MessageListener, :Collection<Topic>) could be called concurrently from the addMessageListener(:MessageListener, Collection<Topic>) method by multiple Threads, and the RedisMessageListenerContainer Javadoc specifically states that it is safe to call the addMessageListener(..) method conurrently without any external synchronization, and the registeration (or mapping) of listener to Topics is a componund action, then a race condition is possible.

Closes spring-projects#2755
@rotilho-bv
Copy link

rotilho-bv commented Jan 18, 2024

I may also be affected by a race condition in RedisMessageListenerContainer. It doesn't happen while debugging the shutdown hook, but it happens every single time I don't. The thread dump makes me believe the error is caused by a race condition during re-registration during shutdown due to messages being sent.

Edit: removing message listener during shutdown workaround the problem.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in:messaging Redis messaging components type: bug A general bug
Projects
None yet
Development

No branches or pull requests

4 participants