微信公众号文章同步到官网
一、业务背景与需求分析1.1 业务背景在企业内容管理系统CMS中微信公众号已成为重要的内容发布渠道。然而许多企业同时拥有官方网站需要将微信公众号发布的文章同步到官网实现内容的统一管理和多渠道分发。1.2 核心需求需求编号需求描述优先级REQ-001支持微信公众号文章发布后自动同步到官网指定栏目高REQ-002支持配置同步频率Cron表达式高REQ-003支持手动触发同步和重试机制高REQ-004记录同步日志支持查询同步状态和统计中REQ-005高并发场景下的分布式锁控制高REQ-006失败重试采用指数退避策略中二、系统架构设计2.1 架构分层┌─────────────────────────────────────────────────────────────────┐ │ 表现层 (Controller) │ │ WechatWebSyncController - REST API 接口 │ ├─────────────────────────────────────────────────────────────────┤ │ 业务层 (Service) │ │ WechatWebSyncService - 同步业务逻辑 │ │ WechatWebSyncLogService - 同步日志管理 │ │ WechatConfigService - 微信配置管理 │ ├─────────────────────────────────────────────────────────────────┤ │ 数据层 (Mapper/Entity) │ │ WechatWebSyncLog - 同步日志实体 │ │ WechatConfig - 微信配置实体 │ │ ChannelContent - 栏目内容关联实体 │ ├─────────────────────────────────────────────────────────────────┤ │ 基础设施层 │ │ RedisLockUtils - Redis分布式锁 │ │ WechatContentConverter - 内容转换器 │ │ AsyncConfiguration - 异步线程池配置 │ └─────────────────────────────────────────────────────────────────┘2.2 核心流程图2.2.1 同步配置流程用户请求 → WechatWebSyncController.setupSync() → 参数校验 → 获取微信站点配置 → 建立栏目引用关系 (ChannelCite) → 创建定时发布规则 (PubTimerRule) → 更新同步配置 → 返回配置信息2.2.2 文章同步流程文章发布事件 → WechatSyncEventHandler → 获取Redis分布式锁 (wechat:sync:lock:{infoId}) → 检查同步状态已成功则跳过 → 更新状态为同步中 → 建立栏目内容关联 (ChannelContent) → 触发官网栏目生成 → 更新状态为成功 → 释放分布式锁2.2.3 定时同步任务流程Cron定时触发 → WechatSyncTask.scheduledSync() → 获取站点同步锁 → 查询待同步和失败的日志 → 异步执行同步 → 失败日志采用指数退避重试 → 释放锁三、核心实现机制3.1 分布式锁控制publicclassWechatWebSyncServiceImpl{privatestaticfinalStringSYNC_LOCK_PREFIXwechat:sync:lock:;privatestaticfinallongLOCK_EXPIRE_SECONDS60;privatestaticfinallongLOCK_WAIT_MILLIS3000;privatevoiddoSync(StringinfoId,Stringwebappcode){StringlockKeySYNC_LOCK_PREFIXinfoId;booleanlockedfalse;try{lockedredisLockUtils.lock(lockKey,LOCK_EXPIRE_SECONDS,LOCK_WAIT_MILLIS);if(!locked){log.warn(获取同步锁失败文章ID{}可能正在同步中,infoId);return;}// 双重检查同步状态WechatWebSyncLoglogEntitywechatWebSyncLogService.getByInfoId(infoId);if(logEntity!nulllogEntity.getSyncStatus()SyncStatus.SUCCESS.getCode()){log.info(文章已同步成功跳过{},infoId);return;}// 执行同步逻辑...}finally{if(locked){redisLockUtils.unlock(lockKey);}}}}设计要点锁粒度文章ID级别确保同一文章不会被重复同步锁超时60秒自动释放防止死锁等待时间3秒最大等待避免线程阻塞双重检查获取锁后再次检查状态防止竞态条件3.2 指数退避重试机制publicclassWechatSyncTask{publicvoidscheduleRetry(WechatWebSyncLoglogEntity){intretryCountlogEntity.getRetryCount()1;long[]delays{60000,300000,1800000};// 1分钟, 5分钟, 30分钟longdelaydelays[Math.min(retryCount-1,delays.length-1)];wechatWebSyncLogService.updateRetryInfo(logEntity.getInfoId(),retryCount,DateUtils.getStringDateTime());wechatWebSyncLogService.updateStatus(logEntity.getInfoId(),SyncStatus.RETRYING.getCode(),null);scheduler.schedule(()-{WechatWebSyncLogcurrentLogwechatWebSyncLogService.getByInfoId(infoId);if(currentLog!nullcurrentLog.getSyncStatus()SyncStatus.RETRYING.getCode()){wechatWebSyncService.syncArticleAsync(infoId,webappcode);}},delay,TimeUnit.MILLISECONDS);}}设计要点最大重试次数3次重试间隔1分钟 → 5分钟 → 30分钟指数增长状态检查重试执行前检查状态防止重复重试3.3 定时任务配置Scheduled(cron${wechat.sync.default-cron:0 0 2 * * ?})publicvoidscheduledSync(){ListWechatConfigconfigswechatConfigService.list();for(WechatConfigconfig:configs){if(config.getSyncEnabled()!1){continue;}StringlockKeyTASK_LOCK_PREFIXconfig.getWebappcode();booleanlockedredisLockUtils.lock(lockKey,LOCK_EXPIRE_SECONDS,LOCK_WAIT_MILLIS);if(!locked){continue;}try{syncSite(config);}finally{redisLockUtils.unlock(lockKey);}}}预设Cron模板模板名称Cron表达式说明每小时0 0 * * * ?每小时整点执行每天0 0 2 * * ?每天凌晨2点执行每周0 0 2 * * MON每周一凌晨2点执行每12小时0 0 2,14 * * ?每天凌晨2点和下午2点执行每30分钟0 0/30 * * * ?每30分钟执行一次四、数据库设计4.1 同步日志表 (wechat_web_sync_log)字段名类型说明索引idvarchar(32)主键IDPRIMARY KEYinfo_idvarchar(32)文章IDUNIQUE KEYwechat_webappcodevarchar(32)微信站点codeINDEXsync_statustinyint同步状态(0-待同步,1-同步中,2-成功,3-失败,4-重试中)INDEXretry_countint重试次数-last_retry_timedatetime最后重试时间-error_msgvarchar(500)错误信息-create_timedatetime创建时间INDEXupdate_timedatetime更新时间-4.2 索引优化策略CREATEUNIQUEINDEXuk_info_idONwechat_web_sync_log(info_id);CREATEINDEXidx_webapp_statusONwechat_web_sync_log(wechat_webappcode,sync_status);CREATEINDEXidx_create_timeONwechat_web_sync_log(create_time);五、API接口设计5.1 接口列表接口路径HTTP方法功能描述/wechat/sync/setupPOST配置同步目标/wechat/sync/configGET获取同步配置/wechat/sync/enablePOST启用同步/wechat/sync/disablePOST禁用同步/wechat/sync/manual/{infoId}POST手动触发同步/wechat/sync/logsGET查询同步日志/wechat/sync/statisticsGET获取同步统计/wechat/sync/retry/{infoId}POST重试失败任务/wechat/sync/cron-templatesGET获取Cron模板5.2 接口示例POST /wechat/sync/setup - 配置同步目标请求体{webappcode:wechat001,syncWebappCode:site001,syncChannelCode:channel001,wechatChannelCode:wechat001001,syncCron:0 0 2 * * ?}响应体{code:0,message:success,data:{id:xxx,webappcode:wechat001,syncEnabled:1,syncWebappCode:site001,syncChannelCode:channel001,syncCron:0 0 2 * * ?,syncTimerRuleId:timer001}}六、高并发场景优化6.1 分布式锁策略┌─────────────────────────────────────────────────────┐ │ 高并发同步场景处理流程 │ ├─────────────────────────────────────────────────────┤ │ │ │ 请求1 ──────┐ │ │ 请求2 ──────┼──→ 获取Redis锁(wechat:sync:lock:{id}) │ │ 请求3 ──────┘ │ │ │ ▼ │ │ 检查锁是否获取成功 │ │ │ │ │ ┌────────┴────────┐ │ │ │ │ │ │ 获取成功 获取失败 │ │ │ │ │ │ ▼ ▼ │ │ 执行同步逻辑 返回同步中 │ │ │ │ │ ▼ │ │ 释放Redis锁 │ │ │ └─────────────────────────────────────────────────────┘6.2 异步线程池配置ConfigurationpublicclassAsyncConfiguration{Bean(wechatSyncExecutor)publicExecutorwechatSyncExecutor(){ThreadPoolTaskExecutorexecutornewThreadPoolTaskExecutor();executor.setCorePoolSize(4);executor.setMaxPoolSize(8);executor.setQueueCapacity(1000);executor.setThreadNamePrefix(wechat-sync-);executor.setRejectedExecutionHandler(newThreadPoolExecutor.CallerRunsPolicy());executor.initialize();returnexecutor;}}线程池参数说明核心线程数4处理正常同步任务最大线程数8应对峰值负载队列容量1000缓冲待同步任务拒绝策略CallerRunsPolicy确保任务不丢失七、总结微信公众号文章同步到官网业务的核心设计要点分布式锁控制使用Redis实现文章级别的分布式锁防止重复同步异步处理使用独立线程池异步执行同步任务提高系统吞吐量指数退避重试失败任务采用1分钟/5分钟/30分钟的指数退避策略重试灵活配置支持Cron表达式配置同步频率提供5种预设模板完整日志记录同步状态、重试次数、错误信息支持统计分析定时任务支持定时批量同步和手动触发同步通过以上设计系统能够在高并发场景下稳定运行确保微信公众号文章准确、及时地同步到官网。