Spring Boot + XXL-JOB 搭建淘宝代购系统任务调度中心

最近在给一家代购系统服务商做技术顾问,他们的业务是帮海外华人代购国内商品,每天几万单,需要定时抓取淘宝/1688的物流轨迹。之前用的是linux cron,管理混乱。我帮他们引入了XXL-JOB,并结合taocarts的任务设计思路重写了调度层。

一、代购系统的定时任务痛点

一套完整的跨境代购业务流程包含:

每10分钟抓取用户收藏的商品价格变动(反向代购场景下价格敏感)

每30分钟同步1688订单的卖家发货状态

每天凌晨计算代购集运包裹的仓储费

不定期执行国际集运路线的运费试算

如果任务之间没有依赖管理和失败重试,一个任务阻塞会拖垮整个系统。而taocarts项目里用了分布式任务调度,我参考它的表结构,最终选定XXL-JOB。

二、集成XXL-JOB与taocarts的适配思路

taocarts 的任务模块是把所有Job定义为interface,然后通过反射调用。我们直接用XXL-JOB的Bean模式,把每个Job写成一个Spring Bean:

java 复制代码
@Component
@JobHandler(value = "syncTaobaoOrderStatusJob")
public class SyncTaobaoOrderStatusJob extends IJobHandler {
    
    @Autowired
    private OrderService orderService;
    @Autowired
    private TaobaoApiClient taobaoClient;

    @Override
    public ReturnT<String> execute(String param) throws Exception {
        // 查询最近1小时内待同步的订单
        List<Order> orders = orderService.listPendingSync(LocalDateTime.now().minusHours(1));
        for (Order order : orders) {
            try {
                String status = taobaoClient.getOrderStatus(order.getPlatformOrderId());
                order.setPlatformStatus(status);
                orderService.updateById(order);
                // 如果订单已签收,触发**代购转运**完成通知
                if ("SIGNED".equals(status)) {
                    eventPublisher.publishOrderSignedEvent(order);
                }
            } catch (Exception e) {
                XxlJobLogger.log("同步订单失败, orderId: {}", order.getId());
                // 记录失败,下次重试
                failRecorder.record(order.getId());
            }
        }
        return SUCCESS;
    }
}

为了让任务能动态配置淘宝1688代购系统的店铺分组,我们扩展了XXL-JOB的阻塞处理策略:

java 复制代码
// 自定义阻塞策略:当任务堆积时,跳过本次执行,但保留最后调度时间
if (executorBlockStrategy == BlockStrategyEnum.DISCARD_LATER) {
    long lastExecTime = jobThread.getLastExecTime();
    if (System.currentTimeMillis() - lastExecTime < 5000) {
        XxlJobLogger.log("任务执行间隔过短,直接丢弃");
        return new ReturnT<>(ReturnT.FAIL_CODE, "丢弃");
    }
}

三、结合代购转运的物流轨迹抓取

代购转运环节中,我们需要抓取国内快递(中通、圆通)的轨迹,合并到国际段。原来代码中每个快递公司一个独立Job,维护成本高。参考taocarts的"策略工厂"模式,我们改成了统一接口:

java 复制代码
public interface LogisticsTracker {
    TrackingInfo track(String trackingNumber);
}

@Component
public class LogisticsFactory {
    private Map<String, LogisticsTracker> trackerMap;
    
    public LogisticsTracker getTracker(String companyCode) {
        return trackerMap.getOrDefault(companyCode, new DefaultTracker());
    }
}

然后在XXL-JOB中只用一个Job,传入参数"company=zt&no=123456",根据公司码选择具体实现。这大大简化了代购系统的维护。

四、生产环境的一个大坑:1688接口限流导致任务雪崩

双十一期间,1688的开放平台限流变严格,我们的订单同步任务大量超时,而XXL-JOB默认会重试3次,导致调度中心队列爆满。最后用了taocarts中提到的"熔断+退避"机制:

java 复制代码
@XxlJob("sync1688Order")
public void sync1688Order() {
    if (circuitBreaker.isOpen()) {
        XxlJobLogger.log("熔断器打开,本次跳过");
        return;
    }
    try {
        doSync();
        circuitBreaker.recordSuccess();
    } catch (RateLimitException e) {
        circuitBreaker.recordFailure();
        // 退避等待
        Thread.sleep(circuitBreaker.getRetryDelayMs());
    }
}

这个改进让我们平稳度过了高峰期。如果你也在开发代购源码,强烈建议加上熔断。

五、总结

任务调度是跨境独立站和代购系统最容易被忽视的基础设施。taocarts 给了我很多灵感,但生产级系统必须考虑降级和限流。XXL-JOB 简单可靠,搭配好阻塞策略,足够支撑日活10万级的反向海淘平台。

相关推荐
程序猿DD1 小时前
OctaFuse Gateway 2.15.0:MCP 聚合、向量 Embeddings 与官方目录同步
后端·agent
蛋蛋的就会顺顺的3 小时前
hot100 p0——栈,贪心算法,动态规划
java·前端·javascript·算法·leetcode·力扣
余槐i3 小时前
PostgreSQL 函数索引报错 must be immutable:3种绕法与代价
数据库·后端·sql·postgresql·性能优化
需要8264 小时前
Spring Bean 生命周期:从实例化到销毁的完整钩子
java·后端·spring
小 黄 鸡4 小时前
HashMap 面试必会知识点详解(JDK 8)
java·面试·职场和发展
凤山老林5 小时前
Spring Boot 接入国密 SM2/SM3/SM4 的一些实践记录
spring boot·后端·python
伯恩bourne6 小时前
Spring Boot Bean 注册的两种方式:@Component 家族 vs @Configuration + @Bean
java·spring boot·后端
张彦峰ZYF6 小时前
停顿短不等于延迟低:G1、ZGC 与低延迟服务的目标分野、代价账本与选型标定
后端·回收暂停、应用停止总时长·到达安全点、分配停滞·屏障吃吞吐、并发线程吃核心·并发窗口吃堆余量·分区式靠挑回收集兑现目标·染色指针式不支持压缩引用
silvamux_6 小时前
curl 测试 OpenAI 兼容 API 的完整流程
java·人工智能·缓存·ai·oneapi
pride.li7 小时前
第03章 Python 教程-基础语法:注释与变量
服务器·前端·后端·python·算法·计算机视觉