yeg
2026-09-17 c46ef64cd3cc90da78bc7946a9a0666d035a680e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
package com.talentcard.server.business.payment;
 
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
 
@Component
public class PaymentReconciliationScheduler {
    private static final Logger log = LoggerFactory.getLogger(PaymentReconciliationScheduler.class);
    private final PaymentReconciliationService service;
    /**
     * 定时对账的开关。
     *
     * <p>默认值取「开」,与 yml 里的 {@code app.payment.huifu.reconciliation.enabled: true} 一致:
     * 此前注解默认关、yml 打开,删掉 yml 里那一行就会让支付与退款唯一的后台兜底**静默消失**。
     * 现在两处默认值相同,删掉那一行也不会把任务关掉。
     */
    @Value("${app.payment.huifu.reconciliation.enabled:true}") private boolean enabled = true;
    @Value("${app.payment.huifu.reconciliation.pending-after-minutes:5}") private int pendingAfterMinutes;
    public PaymentReconciliationScheduler(PaymentReconciliationService service) { this.service = service; }
 
    /**
     * 对账节奏:一分钟一轮。
     *
     * <p>这个间隔决定的是**关单补偿的下限**,不只是「多久查一次」:通道答「关单处理中」的尝试落在
     * {@code CLOSING},用户此刻正看着页面等结论,而关单重试的资格条件是「距上次处理满一分钟」——
     * 扫描本身若五分钟才跑一次,设计里那句「关单每分钟重试一次、最多三次」就变成「每五分钟一次、
     * 最多十五分钟」,用户看到的就是「点了取消一直卡着」。
     *
     * <p>调快不会加重通道负担:慢车道(未定局的支付与退款)每行都带 {@code pending-after-minutes}
     * 与 {@code last_reconciled_at} 双重退避,同一行不会因为扫描变密而被重复查询。
     */
    @Scheduled(fixedDelayString = "${app.payment.huifu.reconciliation.fixed-delay-ms:60000}")
    public void reconcilePendingTransactions() {
        if (!enabled) return;
        try {
            service.reconcile(pendingAfterMinutes);
        } catch (RuntimeException exception) {
            log.warn("Payment reconciliation run failed: {}", exception.getClass().getSimpleName());
        }
    }
}