| | |
| | | import org.springframework.stereotype.Component; |
| | | |
| | | /** |
| | | * 北京时间每日凌晨 00:10 触发前一个自然日的自动提现汇总(cron 的时区固定为北京时间, |
| | | * 不依赖服务器或 JVM 的默认时区)。 |
| | | * 自动提现的定时入口。 |
| | | * |
| | | * <p>每天北京时间 00:10({@code app.merchant.auto-withdrawal.cron},时区固定为北京时间)汇总前一个 |
| | | * 自然日并立即把新记录提交给斗拱;随后每隔一段时间(默认 5 分钟)把还没提交的记录补交一次,并查询 |
| | | * 处理中的记录收敛状态。查询要等记录提交后过了 {@code query-after-minutes} 才进行,避免把通道「还没 |
| | | * 落库」误判成失败。 |
| | | * |
| | | * <p>提交本身是幂等的:只有 {@code pending} 的记录能被认领,重复执行或两个实例并发都不会重复出账。 |
| | | */ |
| | | @Component |
| | | public class AutoWithdrawalScheduler { |
| | | |
| | | private static final Logger log = LoggerFactory.getLogger(AutoWithdrawalScheduler.class); |
| | | |
| | | private final AutoWithdrawalAggregationService service; |
| | | private final AutoWithdrawalAggregationService aggregation; |
| | | private final AutoWithdrawalResultService results; |
| | | private final AutoWithdrawalProperties properties; |
| | | |
| | | public AutoWithdrawalScheduler(AutoWithdrawalAggregationService service, AutoWithdrawalProperties properties) { |
| | | this.service = service; |
| | | public AutoWithdrawalScheduler(AutoWithdrawalAggregationService aggregation, AutoWithdrawalResultService results, |
| | | AutoWithdrawalProperties properties) { |
| | | this.aggregation = aggregation; |
| | | this.results = results; |
| | | this.properties = properties; |
| | | } |
| | | |
| | |
| | | public void aggregateDaily() { |
| | | if (!properties.isEnabled()) return; |
| | | try { |
| | | AutoWithdrawalAggregationService.Result result = service.run(); |
| | | AutoWithdrawalAggregationService.Result result = aggregation.run(); |
| | | log.info("Auto withdrawal aggregation {}", result); |
| | | } catch (RuntimeException exception) { |
| | | log.warn("Auto withdrawal aggregation run failed: {}", exception.getClass().getSimpleName()); |
| | | } |
| | | // 汇总之后马上提交:金额当晚就能动,不用等到下一次轮询。 |
| | | submitPending(); |
| | | } |
| | | |
| | | @Scheduled(fixedDelayString = "${app.merchant.auto-withdrawal.result-check-fixed-delay-ms:300000}") |
| | | public void processResults() { |
| | | if (!properties.isEnabled() || !properties.isResultCheckEnabled()) return; |
| | | submitPending(); |
| | | reconcile(); |
| | | } |
| | | |
| | | private void submitPending() { |
| | | try { |
| | | int submitted = results.submitPending(); |
| | | if (submitted > 0) log.info("Submitted {} auto withdrawals to Huifu", submitted); |
| | | } catch (RuntimeException exception) { |
| | | log.warn("Auto withdrawal submission failed: {}", exception.getClass().getSimpleName()); |
| | | } |
| | | } |
| | | |
| | | private void reconcile() { |
| | | try { |
| | | int settled = results.reconcileProcessing(); |
| | | if (settled > 0) log.info("{} auto withdrawals reached a final state", settled); |
| | | } catch (RuntimeException exception) { |
| | | log.warn("Auto withdrawal result reconciliation failed: {}", exception.getClass().getSimpleName()); |
| | | } |
| | | } |
| | | } |