-
Notifications
You must be signed in to change notification settings - Fork 1.2k
GH-1004 - Scaffold annotation-driven listener architecture #3303
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
base: main
Are you sure you want to change the base?
Conversation
|
Can you sketch out the declaration side of this change (i.e. how would application code look like) so we have an idea how this is going to be used? With such an approach, we can get an idea which components we need to build and how to approach certain aspects of invocation, exception handling and return value handling. |
|
Sure, here is the sketch of the declaration side. ConfigurationThe user enables the infrastructure and defines a @Configuration
@EnableRedisListeners
public class RedisListenerConfig {
@Bean
public RedisListenerContainerFactory<?> redisListenerContainerFactory(RedisConnectionFactory connectionFactory) {
DefaultRedisListenerContainerFactory factory = new DefaultRedisListenerContainerFactory();
factory.setConnectionFactory(connectionFactory);
// Custom Serialization
factory.setObjectMapper(new ObjectMapper());
// Global Error Handling (e.g. logging or dead-lettering)
factory.setErrorHandler(t -> System.err.println("Listener error: " + t.getMessage()));
return factory;
}
}Application Code (The Listener)The developer can simply annotate methods. The infrastructure handles the argument resolution (converting @Service
public class OrderService {
// Simple String listener on a specific channel
@RedisListener(topics = "orders.logs")
public void logOrder(String logMessage) {
System.out.println("Received: " + logMessage);
}
// POJO listener with automatic deserialization (via Jackson/Converter)
@RedisListener(topics = "orders.created", containerFactory = "myCustomFactory")
public void createOrder(OrderEvent event) {
// 'event' is automatically deserialized from the Redis payload
orderRepository.save(event);
}
// Pattern matching listener
@RedisListener(topicPatterns = "orders.*")
public void monitorOrders(Message message) {
// Access raw Spring Data Redis Message object if needed
System.out.println("Activity on channel: " + new String(message.getChannel()));
}
}Handling Invocation & Exceptions
|
|
I'm getting pretty much the impression talking to ChatGPT as the descriptions and comments are a wall of text sumarizing themselves discussing obvious details from the JMS listeners without considering Redis-specifics. The actually interesting questions are:
If you would like us to spend some time collaborating with you, please spend some time and effort. We appreciate community contributions, but we do need them to meet a reasonable baseline for consideration. This means:
Writing the code is not a problem to be solved, we can throw a few sentences into an LLM ourselves. Listening, understanding, and activiating creativity to address a genuine concern is what matters when developing libraries for a broader audience. When contributions require significant rework from our side, we have to deprioritize or even reject them in favor of changes that are ready for integration as we have to be mindful of our limited time, and we need to focus it where it has the most impact. If you would like us to spend some time working on this pull request, please spend some time making this a substantial and quality contribution. |
|
Point taken. I appreciate the direct feedback regarding the contribution baseline; I intended to align on the high-level API first, but I see now that glossing over the runtime specifics made the proposal feel abstract. To answer your technical constraints directly: A single On the data side, we need to support I will pivot the PR to focus entirely on this argument resolution and deserialization strategy, as that is clearly where the complexity lies. |
|
Thanks for your suggestion. So a single annotation to indicate pattern or channel subscriptions:
These could be also mixed and we would define once there are placeholders, we're using Pattern subscriptions. Injectable argument types:
I think we should also consider @Controller
public class MyController {
// ...
@RedisExceptionHandler
public void handleException(MyException exception) {
// ...
}
}I think this arrangement is sufficient for the very initial step to get something going and already bears quite some complexity. Spring Framework provides a Let's take another step back to see the greater picture. Right now, we're discussing Redis Pub/Sub. In that context, |
|
That sounds like a solid plan. I agree that keeping the scope tight (focusing on the registration and invocation mechanics while sticking to simple types first) is the best way to stabilize the core before tackling the serialization ambiguity. Regarding the naming, I think sticking with The addition of |
Signed-off-by: Ilyass-Bougati <[email protected]>
Change validation from checking nanosecond component to comparing the entire Duration against Duration.ofSeconds(1). This allows Duration values like 1.5 seconds or Duration.ofMillis(1001) to be correctly accepted. Closes spring-projects#2975 Original Pull Request spring-projects#3302 Signed-off-by: CHANHAN <[email protected]> Signed-off-by: Ilyass-Bougati <[email protected]>
- Move timeout related tests into parameterized unit test. - Move isZeroOrGreaterOneSecond into TimeoutUtils and simplify the tests. See spring-projects#2975 Original Pull Request spring-projects#3302 Signed-off-by: Chris Bono <[email protected]> Signed-off-by: Ilyass-Bougati <[email protected]>
See spring-projects#3264 Signed-off-by: Ilyass-Bougati <[email protected]>
…structure Signed-off-by: Ilyass-Bougati <[email protected]>
…eaders Signed-off-by: Ilyass-Bougati <[email protected]>
Relates to #1004
Purpose
Following the discussion in #1004 and the suggestion by @onobc, this PR introduces the high-level architectural skeleton for the annotation-driven listener model.
The goal is to align on the core components and interfaces before filling in the implementation logic.
Design Overview
To ensure consistency with the wider Spring ecosystem, this design strictly mirrors the Listener Container Factory pattern found in
spring-jmsandspring-amqp. This approach decouples the listener model from the execution, allowing for granular configuration (thread pools, serializers) per listener.Introduced Components:
RedisListenerContainerFactory: Strategy interface for creatingRedisMessageListenerContainerinstances.RedisListenerEndpoint: The model describing a listener configuration.RedisListenerEndpointRegistry: Lifecycle manager for the created containers.RedisListenerAnnotationBeanPostProcessor: Infrastructure bean that detects@RedisListenermethods and registers endpoints.@EnableRedisListeners: Configuration annotation to activate the post-processor.Note on Testing
Per the discussion in #1004, this is a high-level design proposal containing only interfaces and skeleton classes. No test cases are included in this PR as there is no implementation logic yet. Comprehensive unit and integration tests will be added in the subsequent implementation PRs.