Introducing Redis Pub/Sub for System Date Changes in Testing

Introduction
Hello! My name is Yoo, and I am a member of the New Car Subscription Development Group at KINTO Technologies.
While our approach may not be perfect, we continuously strive to improve challenges step by step. In this article, I’d like to share how we implemented Redis Pub/Sub in Spring Boot to dynamically change the system date.
Background and Motivation
When conducting QA and testing, there are many cases where it is necessary to change the system date to verify specific behaviors. This is especially important for subscription-based services, where business logic often depends on specific dates. For example, testing requires validation of processes related to start and end dates of the period, monthly fees, settlement charges for mid-term cancellations, maintenance inspections, and vehicle inspections. Previously, the system date was defined in the configuration file, meaning that every time the date needed to be changed, the container had to be redeployed. As a result, each test or QA cycle required more than five minutes just for redeployment, significantly impacting efficiency. In this article, I will introduce how we solved this issue and improved our workflow.
Benefits of introducing Redis Pub/Sub
By implementing Redis Pub/Sub, we optimized system date changes in test environments, making them more efficient and responsive. As a result, we have successfully reduced the workload for testing and QA, leading to improved operational efficiency. Specifically, container redeployment is no longer required. Instead, by simply sending a message (the desired setting value) to the corresponding setting item (topic), each container can instantly receive the update and apply the changes in real time. Even in multi-container environments, all subscribers receive the message simultaneously, allowing system settings to be updated across multiple containers without requiring a restart.
Additionally, system date changes are now logged, making it possible to track and review change history when needed. Furthermore, with Spring Boot Profile settings, this feature can be enabled exclusively in designated test environments, preventing accidental application to production or other environments. *For more details on Profiles, see here.
What is Redis Pub/Sub
Redis Pub/Sub is one of the messaging patterns used in message queuing systems. Message Queuing is a method of asynchronous communication commonly used in serverless and microservices architectures to enable real-time event notification in distributed systems. This mechanism is widely used not only as a database and cache but also as a message broker, as it supports scalable and stable communication between different software modules.
Main components
- Topic: The subject or category that subscribers listen to.
- Publisher: Sends messages related to a specific topic.
- Subscriber: Receives messages from publishers for subscribed topics.
Keyspace Notifications
Redis can monitor real-time changes to keys and values by receiving events that impact the Redis dataset in various ways.
How is it implemented?
System date change mechanism
We implemented an API as a publisher to send messages to designated topics. When an event occurs for a subscribed topic (key), multiple containers (subscribers) receive the message and update the settings in real time.
System configuration
It is built using Java and Spring Boot. Applications are containerized and run in a cloud environment.
Adding the necessary library to build.gradle
implementation 'org.springframework.data:spring-data-redis'
Implementing the RedisConfig class
@AllArgsConstructor
@Configuration
public class RedisTemplateConfig {
private final RedissonClient redissonClient;
@Bean
public RedisTemplate<String, String> redisTemplate() {
RedisTemplate<String, String> template = new RedisTemplate<>();
template.setConnectionFactory(new RedissonConnectionFactory(redissonClient));
template.setDefaultSerializer(new StringRedisSerializer());
return template;
}
@Bean
public RedisMessageListenerContainer redisContainer() {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(new RedissonConnectionFactory(redissonClient));
return container;
}
}
Implementing the Publisher
Implement an API that sends messages to a designated topic.
@RestController
public class SystemTimeController {
private final SomeService service;
@PostMapping("/update")
public void updateSystemTime(@RequestParam String specifiedDateTime) {
service.publish(specifiedDateTime);
}
}
@Service
@RequiredArgsConstructor
public class SomeService {
private final RedisTemplate<String, String> redisTemplate;
// Define the topic key
private static final String FOO_TOPIC = "foo-key";
public void publish(String specifiedDateTime) {
// Send a message to the specified topic
redisTemplate.opsForValue().set(FOO_TOPIC, specifiedDateTime);
}
}
Implementing the Subscriber
The subscriber receives messages when an event occurs for a subscribed topic (key).
@Slf4j
@Component
@Profile("developer1, developer2") // Only enabled for the specified test environment profiles
public class FooKeyspaceEventMessageListener extends KeyspaceEventMessageListener {
private final RedisMessageListenerContainer listenerContainer;
private final RedisTemplate<String, String> redisTemplate;
private static final String FOO_TOPIC = "foo-key";
@Override
public void init() {
doRegister(listenerContainer);
}
public FooKeyspaceEventMessageListener(
RedisMessageListenerContainer listenerContainer,
RedisTemplate<String, String> redisTemplate) {
super(listenerContainer);
this.listenerContainer = listenerContainer;
this.redisTemplate = redisTemplate;
}
@Override
protected void doHandleMessage(Message message) {
// Retrieve the system date from Redis
String systemTime = updateSystemTimeConfig(redisTemplate.opsForValue().get(FOO_TOPIC));
// Create and invoke the method to update the system date
updateSystemTimeConfig(systemTime);
log.info("Receive a message about FOO_TOPIC: {}", message);
}
}
Finally
Thank you for reading this article to the end. There are still many areas for improvement, but we strive to address challenges step by step and grow with each iteration. While the structure and implementation may not be perfect, I believe that gradual progress in the right direction is what truly matters. We will continue to learn, ensuring that these small advancements accumulate and lead to even better outcomes. I hope we can continue this journey of growth together. Thank you very much.