KINTO Tech Blog
Development

Introducing Redis Pub/Sub for System Date Changes in Testing

Cover Image for 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 Date Change Architecture

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.

Facebook

関連記事 | Related Posts

イベント情報

P3NFEST Bug Bounty 2025 Winter 【KINTOテクノロジーズ協賛】