Backend Development 8 min read

Designing a Distributed MQ-Based Retry Mechanism with Annotations and AOP

This article explains how to implement a robust distributed retry mechanism using message queues, annotations, and AOP, providing configurable options, visual monitoring, and code examples to help developers achieve eventual consistency with minimal boilerplate.

Zhuanzhuan Tech
Zhuanzhuan Tech
Zhuanzhuan Tech
Designing a Distributed MQ-Based Retry Mechanism with Annotations and AOP

Background : In distributed scenarios, ensuring system availability and eventual data consistency often relies on a retry mechanism based on a message queue (MQ). The article presents pseudocode that demonstrates how a failed transaction can be serialized, sent to an MQ, and retried by a consumer.

The example shows business‑agnostic code that developers must write to achieve retry, and argues for abstracting and optimizing this boilerplate to reduce developer burden and improve code quality.

Solution : The retry logic is encapsulated so that developers only need to annotate a method that must guarantee eventual consistency with @MQRetry . The framework then provides distributed retry capabilities via MQ.

The implementation follows several steps:

1. Use annotations and AOP : By applying an annotation and leveraging Aspect‑Oriented Programming, the retry logic is decoupled from business code, allowing automatic triggering of retries.

2. Provide configurable options : Parameters such as maximum retry attempts and retry intervals can be configured without code changes.

3. Exception handling and logging : Properly handle exceptions and record logs to aid troubleshooting.

4. Offer a visual monitoring tool : A dashboard tracks retry operations and related metrics in real time.

Effect : Introducing the @MQRetry annotation marks a business method for retry. When the method throws an exception, the framework automatically sends an MQ retry message containing service name, class, method, and arguments. Any server instance can consume the message and re‑execute the method, ensuring eventual consistency.

/**
 * 需要保证最终一致性的函数
 */
public void doSomething(Object args) {
    try {
        // 执行事务的操作
        executeTransaction();
        // 提交事务
        commitTransaction();
    } catch (Exception e) {
        // 回滚事务
        rollbackTransaction();
        // 记录日志
        log.error(e);
        // 序列化参数
        byte[] body = serialize(args);
        // 构建消息, 指定Topic、Body
        Message msg = new Message("doSomethingTopic", body);
        // 发送失败重试消息
        mq.send(msg);
    }
}

/**
 * 消费者,用于失败重试处理
 */
@Consumer(topic = "doSomethingTopic")
public void consume(Message msg) {
    // 反序列化
    Object args = msg.deserialize();
    // 重试
    doSomething(args);
}

Additional optional features include a configurable annotation definition:

/**
 * 基于MQ的分布式重试组件
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MQRetry {
    /** 最大重试次数,默认上限为16次 */
    int maxAttempts() default 16;
    /** 忽略的异常类列表,默认所有异常都重试 */
    Class
[] exclude() default {};
    /** 需要重试的异常类列表,默认所有异常都重试 */
    Class
[] include() default {};
    /** 出现异常时的处理函数, 格式: Bean名.方法名 */
    String errorHandler() default "";
    /** true: 第一次调用时同步执行@MQRetry函数, 失败再使用MQ */
    boolean firstSyncCall() default true;
    /** 消费线程数,默认为20个 */
    int consumeThread() default 20;
}

Precautions :

Suitable for asynchronous scenarios; retry methods should not return values because the return value is ignored.

Ensure idempotency of retry methods ("At least Once" guarantee).

Because AOP proxies are used, the same constraints as @Transactional apply: calls via this , private methods, or final methods will not be intercepted.

If new parameters are added, they must be appended at the end; historic messages will receive null for the new parameters.

Conclusion : Retry mechanisms are essential for reliable systems and can be implemented in two modes—client‑side and server‑side. While the client mode is simpler, the server‑side approach (as demonstrated) offers higher reliability. Selecting the appropriate mode and tuning configuration yields better performance and user experience.

backenddistributed systemsJavaAOPretryMQ
Zhuanzhuan Tech
Written by

Zhuanzhuan Tech

A platform for Zhuanzhuan R&D and industry peers to learn and exchange technology, regularly sharing frontline experience and cutting‑edge topics. We welcome practical discussions and sharing; contact waterystone with any questions.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.