PersonnelSyncTimer.java 3.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. package com.malk.timer;
  2. import com.malk.service.personnel.PersonnelSyncService;
  3. import lombok.extern.slf4j.Slf4j;
  4. import org.springframework.beans.factory.annotation.Autowired;
  5. import org.springframework.context.annotation.Configuration;
  6. import org.springframework.scheduling.annotation.EnableScheduling;
  7. import org.springframework.scheduling.annotation.Scheduled;
  8. import java.util.concurrent.atomic.AtomicBoolean;
  9. /**
  10. * 钉钉 -> 宜搭 人员档案 定时全量增量同步
  11. * 工作日 (MON-FRI) 每天 08:00 / 13:00 / 18:00 各一次 fullSync (limit 取配置 personnel-sync.limitFirstN, 生产为 0 即真·全量)
  12. * 共 3 次/工作日; 周末不跑
  13. */
  14. @Slf4j
  15. @Configuration
  16. @EnableScheduling
  17. public class PersonnelSyncTimer {
  18. @Autowired
  19. private PersonnelSyncService personnelSyncService;
  20. // fixme: 防止上一轮未完成时下一轮重入 (两轮并发会使 QPS 翻倍)
  21. private final AtomicBoolean running = new AtomicBoolean(false);
  22. // fixme: 钉钉整点 QPS 高峰偶发 subcode=90002 限流 → 首次失败后再重试 2 次, 间隔 60s 让钉钉冷却; 仍失败放弃等下一次 cron
  23. private static final int MAX_ATTEMPTS = 3;
  24. private static final long RETRY_DELAY_MS = 60_000L;
  25. /** 工作日 08:00 / 13:00 / 18:00 各一次全量同步(单方法挂 3 条 cron,离散时点无法用单条 cron 表达) */
  26. @Scheduled(cron = "0 0 8 ? * MON-FRI")
  27. @Scheduled(cron = "0 0 13 ? * MON-FRI")
  28. @Scheduled(cron = "0 0 18 ? * MON-FRI")
  29. public void scheduledFullSync() {
  30. runFullSync("08/13/18");
  31. }
  32. private void runFullSync(String tag) {
  33. if (!running.compareAndSet(false, true)) {
  34. log.warn("[PersonnelSync] 上次定时同步尚未结束,跳过本次触发 tag={}", tag);
  35. return;
  36. }
  37. log.info("[PersonnelSync] 定时同步任务开始 tag={}", tag);
  38. try {
  39. for (int attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {
  40. try {
  41. java.util.Map<String, Object> stats = personnelSyncService.fullSync(null);
  42. log.info("[PersonnelSync] 定时同步任务完成 tag={} attempt={}/{} {}", tag, attempt, MAX_ATTEMPTS, stats);
  43. return;
  44. } catch (Exception e) {
  45. log.error("[PersonnelSync] 定时同步任务失败 tag={} attempt={}/{}", tag, attempt, MAX_ATTEMPTS, e);
  46. if (attempt < MAX_ATTEMPTS) {
  47. try {
  48. Thread.sleep(RETRY_DELAY_MS);
  49. } catch (InterruptedException ie) {
  50. Thread.currentThread().interrupt();
  51. log.warn("[PersonnelSync] 重试等待被中断,放弃本轮 tag={}", tag);
  52. return;
  53. }
  54. }
  55. }
  56. }
  57. log.error("[PersonnelSync] 定时同步任务连续 {} 次失败,放弃本轮等待下一次 cron 触发 tag={}", MAX_ATTEMPTS, tag);
  58. } finally {
  59. running.set(false);
  60. }
  61. }
  62. }