ai-engineering-init 1.3.3 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/hooks/skill-forced-eval.js +4 -1
- package/.claude/settings.json +3 -3
- package/.claude/skills/add-skill/SKILL.md +252 -116
- package/.claude/skills/api-development/SKILL.md +83 -377
- package/.claude/skills/architecture-design/SKILL.md +138 -632
- package/.claude/skills/backend-annotations/SKILL.md +134 -506
- package/.claude/skills/banana-image/SKILL.md +10 -3
- package/.claude/skills/brainstorm/SKILL.md +103 -535
- package/.claude/skills/bug-detective/SKILL.md +147 -1097
- package/.claude/skills/bug-detective/references/error-patterns.md +242 -0
- package/.claude/skills/code-patterns/SKILL.md +116 -426
- package/.claude/skills/code-patterns/references/leniu-code-patterns.md +87 -0
- package/.claude/skills/crud-development/SKILL.md +64 -304
- package/.claude/skills/data-permission/SKILL.md +105 -412
- package/.claude/skills/data-permission/references/custom-data-scope.md +90 -0
- package/.claude/skills/file-oss-management/SKILL.md +106 -714
- package/.claude/skills/file-oss-management/references/entities.md +105 -0
- package/.claude/skills/file-oss-management/references/service-impl.md +104 -0
- package/.claude/skills/leniu-api-development/SKILL.md +142 -626
- package/.claude/skills/leniu-api-development/references/real-examples.md +273 -0
- package/.claude/skills/leniu-architecture-design/SKILL.md +176 -391
- package/.claude/skills/leniu-backend-annotations/SKILL.md +132 -519
- package/.claude/skills/leniu-brainstorm/SKILL.md +132 -541
- package/.claude/skills/leniu-brainstorm/references/business-scenarios.md +162 -0
- package/.claude/skills/leniu-crud-development/SKILL.md +232 -938
- package/.claude/skills/leniu-crud-development/references/templates.md +597 -0
- package/.claude/skills/leniu-customization-location/SKILL.md +410 -0
- package/.claude/skills/leniu-data-permission/SKILL.md +70 -0
- package/.claude/skills/leniu-java-entity/SKILL.md +76 -590
- package/.claude/skills/leniu-java-entity/references/templates.md +237 -0
- package/.claude/skills/leniu-java-export/SKILL.md +94 -379
- package/.claude/skills/leniu-java-logging/SKILL.md +106 -709
- package/.claude/skills/leniu-java-logging/references/data-mask.md +46 -0
- package/.claude/skills/leniu-java-logging/references/logging-scenarios.md +113 -0
- package/.claude/skills/leniu-java-mybatis/SKILL.md +73 -446
- package/.claude/skills/leniu-java-mybatis/references/report-mapper.md +88 -0
- package/.claude/skills/leniu-report-customization/SKILL.md +111 -325
- package/.claude/skills/leniu-report-customization/references/table-fields.md +93 -0
- package/.claude/skills/leniu-report-standard-customization/SKILL.md +328 -0
- package/.claude/skills/leniu-report-standard-customization/references/analysis-module.md +64 -0
- package/.claude/skills/leniu-report-standard-customization/references/table-fields.md +113 -0
- package/.claude/skills/leniu-security-guard/SKILL.md +133 -347
- package/.claude/skills/mysql-debug/SKILL.md +364 -0
- package/.claude/skills/openspec-apply-change/SKILL.md +10 -1
- package/.claude/skills/openspec-archive-change/SKILL.md +9 -1
- package/.claude/skills/openspec-bulk-archive-change/SKILL.md +9 -1
- package/.claude/skills/openspec-continue-change/SKILL.md +9 -1
- package/.claude/skills/openspec-explore/SKILL.md +10 -1
- package/.claude/skills/openspec-ff-change/SKILL.md +9 -1
- package/.claude/skills/openspec-new-change/SKILL.md +9 -1
- package/.claude/skills/openspec-onboard/SKILL.md +15 -130
- package/.claude/skills/openspec-sync-specs/SKILL.md +9 -1
- package/.claude/skills/openspec-verify-change/SKILL.md +9 -1
- package/.claude/skills/performance-doctor/SKILL.md +110 -434
- package/.claude/skills/redis-cache/SKILL.md +89 -595
- package/.claude/skills/redis-cache/references/listeners.md +23 -0
- package/.claude/skills/scheduled-jobs/SKILL.md +88 -407
- package/.claude/skills/security-guard/SKILL.md +137 -532
- package/.claude/skills/security-guard/references/encrypt-config.md +103 -0
- package/.claude/skills/security-guard/references/sensitive-strategies.md +42 -0
- package/.claude/skills/sms-mail/SKILL.md +116 -574
- package/.claude/skills/sms-mail/references/mail-config.md +88 -0
- package/.claude/skills/sms-mail/references/sms-config.md +74 -0
- package/.claude/skills/social-login/SKILL.md +112 -514
- package/.claude/skills/social-login/references/provider-configs.md +118 -0
- package/.claude/skills/tenant-management/SKILL.md +129 -444
- package/.claude/skills/tenant-management/references/tenant-scenarios.md +91 -0
- package/.claude/skills/test-development/SKILL.md +86 -540
- package/.claude/skills/test-development/references/parameterized-examples.md +119 -0
- package/.claude/skills/utils-toolkit/SKILL.md +52 -305
- package/.claude/skills/utils-toolkit/references/redis-utils-api.md +56 -0
- package/.claude/skills/websocket-sse/SKILL.md +105 -550
- package/.claude/skills/workflow-engine/SKILL.md +147 -502
- package/.codex/skills/add-skill/SKILL.md +252 -116
- package/.codex/skills/api-development/SKILL.md +172 -599
- package/.codex/skills/architecture-design/SKILL.md +138 -504
- package/.codex/skills/backend-annotations/SKILL.md +134 -496
- package/.codex/skills/banana-image/SKILL.md +10 -3
- package/.codex/skills/brainstorm/SKILL.md +103 -535
- package/.codex/skills/bug-detective/SKILL.md +147 -1097
- package/.codex/skills/bug-detective/references/error-patterns.md +242 -0
- package/.codex/skills/code-patterns/SKILL.md +120 -282
- package/.codex/skills/code-patterns/references/leniu-code-patterns.md +87 -0
- package/.codex/skills/crud-development/SKILL.md +64 -292
- package/.codex/skills/data-permission/SKILL.md +108 -407
- package/.codex/skills/data-permission/references/custom-data-scope.md +90 -0
- package/.codex/skills/database-ops/SKILL.md +8 -154
- package/.codex/skills/error-handler/SKILL.md +10 -0
- package/.codex/skills/file-oss-management/SKILL.md +106 -714
- package/.codex/skills/file-oss-management/references/entities.md +105 -0
- package/.codex/skills/file-oss-management/references/service-impl.md +104 -0
- package/.codex/skills/git-workflow/SKILL.md +27 -5
- package/.codex/skills/leniu-api-development/SKILL.md +142 -626
- package/.codex/skills/leniu-api-development/references/real-examples.md +273 -0
- package/.codex/skills/leniu-architecture-design/SKILL.md +176 -391
- package/.codex/skills/leniu-backend-annotations/SKILL.md +132 -519
- package/.codex/skills/leniu-brainstorm/SKILL.md +132 -541
- package/.codex/skills/leniu-brainstorm/references/business-scenarios.md +162 -0
- package/.codex/skills/leniu-crud-development/SKILL.md +232 -938
- package/.codex/skills/leniu-crud-development/references/templates.md +597 -0
- package/.codex/skills/leniu-customization-location/SKILL.md +410 -0
- package/.codex/skills/leniu-data-permission/SKILL.md +70 -0
- package/.codex/skills/leniu-java-code-style/SKILL.md +510 -0
- package/.codex/skills/leniu-java-entity/SKILL.md +76 -590
- package/.codex/skills/leniu-java-entity/references/templates.md +237 -0
- package/.codex/skills/leniu-java-export/SKILL.md +94 -379
- package/.codex/skills/leniu-java-logging/SKILL.md +106 -709
- package/.codex/skills/leniu-java-logging/references/data-mask.md +46 -0
- package/.codex/skills/leniu-java-logging/references/logging-scenarios.md +113 -0
- package/.codex/skills/leniu-java-mybatis/SKILL.md +73 -446
- package/.codex/skills/leniu-java-mybatis/references/report-mapper.md +88 -0
- package/.codex/skills/leniu-report-customization/SKILL.md +111 -325
- package/.codex/skills/leniu-report-customization/references/table-fields.md +93 -0
- package/.codex/skills/leniu-report-standard-customization/SKILL.md +328 -0
- package/.codex/skills/leniu-report-standard-customization/references/analysis-module.md +64 -0
- package/.codex/skills/leniu-report-standard-customization/references/table-fields.md +113 -0
- package/.codex/skills/leniu-security-guard/SKILL.md +133 -347
- package/.codex/skills/mysql-debug/SKILL.md +364 -0
- package/.codex/skills/openspec-apply-change/SKILL.md +10 -1
- package/.codex/skills/openspec-archive-change/SKILL.md +9 -1
- package/.codex/skills/openspec-bulk-archive-change/SKILL.md +9 -1
- package/.codex/skills/openspec-continue-change/SKILL.md +9 -1
- package/.codex/skills/openspec-explore/SKILL.md +10 -1
- package/.codex/skills/openspec-ff-change/SKILL.md +9 -1
- package/.codex/skills/openspec-new-change/SKILL.md +9 -1
- package/.codex/skills/openspec-onboard/SKILL.md +15 -130
- package/.codex/skills/openspec-sync-specs/SKILL.md +9 -1
- package/.codex/skills/openspec-verify-change/SKILL.md +9 -1
- package/.codex/skills/performance-doctor/SKILL.md +110 -434
- package/.codex/skills/project-navigator/SKILL.md +20 -1
- package/.codex/skills/redis-cache/SKILL.md +93 -589
- package/.codex/skills/redis-cache/references/listeners.md +23 -0
- package/.codex/skills/scheduled-jobs/SKILL.md +88 -407
- package/.codex/skills/security-guard/SKILL.md +141 -527
- package/.codex/skills/security-guard/references/encrypt-config.md +103 -0
- package/.codex/skills/security-guard/references/sensitive-strategies.md +42 -0
- package/.codex/skills/sms-mail/SKILL.md +116 -574
- package/.codex/skills/sms-mail/references/mail-config.md +88 -0
- package/.codex/skills/sms-mail/references/sms-config.md +74 -0
- package/.codex/skills/social-login/SKILL.md +112 -514
- package/.codex/skills/social-login/references/provider-configs.md +118 -0
- package/.codex/skills/store-pc/SKILL.md +258 -383
- package/.codex/skills/tenant-management/SKILL.md +129 -444
- package/.codex/skills/tenant-management/references/tenant-scenarios.md +91 -0
- package/.codex/skills/test-development/SKILL.md +86 -540
- package/.codex/skills/test-development/references/parameterized-examples.md +119 -0
- package/.codex/skills/ui-pc/SKILL.md +350 -387
- package/.codex/skills/utils-toolkit/SKILL.md +52 -283
- package/.codex/skills/utils-toolkit/references/redis-utils-api.md +56 -0
- package/.codex/skills/websocket-sse/SKILL.md +105 -550
- package/.codex/skills/workflow-engine/SKILL.md +147 -502
- package/.cursor/hooks.json +3 -3
- package/.cursor/rules/skill-activation.mdc +2 -0
- package/.cursor/skills/add-skill/SKILL.md +252 -116
- package/.cursor/skills/api-development/SKILL.md +83 -377
- package/.cursor/skills/architecture-design/SKILL.md +138 -632
- package/.cursor/skills/backend-annotations/SKILL.md +134 -506
- package/.cursor/skills/banana-image/SKILL.md +10 -3
- package/.cursor/skills/brainstorm/SKILL.md +103 -535
- package/.cursor/skills/bug-detective/SKILL.md +147 -1097
- package/.cursor/skills/bug-detective/references/error-patterns.md +242 -0
- package/.cursor/skills/code-patterns/SKILL.md +116 -426
- package/.cursor/skills/code-patterns/references/leniu-code-patterns.md +87 -0
- package/.cursor/skills/crud-development/SKILL.md +64 -304
- package/.cursor/skills/data-permission/SKILL.md +105 -412
- package/.cursor/skills/data-permission/references/custom-data-scope.md +90 -0
- package/.cursor/skills/file-oss-management/SKILL.md +106 -714
- package/.cursor/skills/file-oss-management/references/entities.md +105 -0
- package/.cursor/skills/file-oss-management/references/service-impl.md +104 -0
- package/.cursor/skills/git-workflow/SKILL.md +27 -5
- package/.cursor/skills/leniu-api-development/SKILL.md +142 -626
- package/.cursor/skills/leniu-api-development/references/real-examples.md +273 -0
- package/.cursor/skills/leniu-architecture-design/SKILL.md +176 -391
- package/.cursor/skills/leniu-backend-annotations/SKILL.md +132 -519
- package/.cursor/skills/leniu-brainstorm/SKILL.md +132 -541
- package/.cursor/skills/leniu-brainstorm/references/business-scenarios.md +162 -0
- package/.cursor/skills/leniu-crud-development/SKILL.md +232 -938
- package/.cursor/skills/leniu-crud-development/references/templates.md +597 -0
- package/.cursor/skills/leniu-customization-location/SKILL.md +410 -0
- package/.cursor/skills/leniu-data-permission/SKILL.md +70 -0
- package/.cursor/skills/leniu-java-code-style/SKILL.md +510 -0
- package/.cursor/skills/leniu-java-entity/SKILL.md +76 -590
- package/.cursor/skills/leniu-java-entity/references/templates.md +237 -0
- package/.cursor/skills/leniu-java-export/SKILL.md +94 -379
- package/.cursor/skills/leniu-java-logging/SKILL.md +106 -709
- package/.cursor/skills/leniu-java-logging/references/data-mask.md +46 -0
- package/.cursor/skills/leniu-java-logging/references/logging-scenarios.md +113 -0
- package/.cursor/skills/leniu-java-mybatis/SKILL.md +73 -446
- package/.cursor/skills/leniu-java-mybatis/references/report-mapper.md +88 -0
- package/.cursor/skills/leniu-report-customization/SKILL.md +111 -325
- package/.cursor/skills/leniu-report-customization/references/table-fields.md +93 -0
- package/.cursor/skills/leniu-report-standard-customization/SKILL.md +328 -0
- package/.cursor/skills/leniu-report-standard-customization/references/analysis-module.md +64 -0
- package/.cursor/skills/leniu-report-standard-customization/references/table-fields.md +113 -0
- package/.cursor/skills/leniu-security-guard/SKILL.md +133 -347
- package/.cursor/skills/mysql-debug/SKILL.md +364 -0
- package/.cursor/skills/openspec-apply-change/SKILL.md +10 -1
- package/.cursor/skills/openspec-archive-change/SKILL.md +9 -1
- package/.cursor/skills/openspec-bulk-archive-change/SKILL.md +9 -1
- package/.cursor/skills/openspec-continue-change/SKILL.md +9 -1
- package/.cursor/skills/openspec-explore/SKILL.md +10 -1
- package/.cursor/skills/openspec-ff-change/SKILL.md +9 -1
- package/.cursor/skills/openspec-new-change/SKILL.md +9 -1
- package/.cursor/skills/openspec-onboard/SKILL.md +15 -130
- package/.cursor/skills/openspec-sync-specs/SKILL.md +9 -1
- package/.cursor/skills/openspec-verify-change/SKILL.md +9 -1
- package/.cursor/skills/performance-doctor/SKILL.md +110 -434
- package/.cursor/skills/redis-cache/SKILL.md +89 -595
- package/.cursor/skills/redis-cache/references/listeners.md +23 -0
- package/.cursor/skills/scheduled-jobs/SKILL.md +88 -407
- package/.cursor/skills/security-guard/SKILL.md +137 -532
- package/.cursor/skills/security-guard/references/encrypt-config.md +103 -0
- package/.cursor/skills/security-guard/references/sensitive-strategies.md +42 -0
- package/.cursor/skills/sms-mail/SKILL.md +116 -574
- package/.cursor/skills/sms-mail/references/mail-config.md +88 -0
- package/.cursor/skills/sms-mail/references/sms-config.md +74 -0
- package/.cursor/skills/social-login/SKILL.md +112 -514
- package/.cursor/skills/social-login/references/provider-configs.md +118 -0
- package/.cursor/skills/tenant-management/SKILL.md +129 -444
- package/.cursor/skills/tenant-management/references/tenant-scenarios.md +91 -0
- package/.cursor/skills/test-development/SKILL.md +86 -540
- package/.cursor/skills/test-development/references/parameterized-examples.md +119 -0
- package/.cursor/skills/utils-toolkit/SKILL.md +52 -305
- package/.cursor/skills/utils-toolkit/references/redis-utils-api.md +56 -0
- package/.cursor/skills/websocket-sse/SKILL.md +105 -550
- package/.cursor/skills/workflow-engine/SKILL.md +147 -502
- package/AGENTS.md +1 -0
- package/package.json +1 -1
|
@@ -4,7 +4,7 @@ description: |
|
|
|
4
4
|
定时任务开发指南。涵盖 @Scheduled、SnailJob 两种方案,支持分布式任务调度、失败重试、工作流编排。
|
|
5
5
|
|
|
6
6
|
触发场景:
|
|
7
|
-
-
|
|
7
|
+
- 每日数据汇总、定期清理等周期性任务
|
|
8
8
|
- 分布式复杂业务、失败重试、可视化管理(SnailJob)
|
|
9
9
|
- 任务分片、Map/MapReduce 分布式计算
|
|
10
10
|
- 广播任务(所有节点执行)
|
|
@@ -12,108 +12,26 @@ description: |
|
|
|
12
12
|
触发词:定时任务、SnailJob、任务调度、重试机制、工作流、@JobExecutor、@Scheduled、分布式任务、广播任务、分片任务、MapReduce
|
|
13
13
|
|
|
14
14
|
核心特性:
|
|
15
|
-
-
|
|
16
|
-
-
|
|
15
|
+
- @Scheduled:简单周期任务、框架内置
|
|
16
|
+
- SnailJob:分布式集群、可视化管理、失败重试、工作流编排
|
|
17
17
|
---
|
|
18
18
|
|
|
19
19
|
# 定时任务开发指南
|
|
20
20
|
|
|
21
21
|
> 模块位置:`ruoyi-modules/ruoyi-job`
|
|
22
22
|
|
|
23
|
-
##
|
|
23
|
+
## 方案选择
|
|
24
24
|
|
|
25
|
-
| 场景 |
|
|
26
|
-
|
|
27
|
-
| 简单周期任务(日报、清理) | `@Scheduled` |
|
|
28
|
-
|
|
|
29
|
-
|
|
|
30
|
-
|
|
|
25
|
+
| 场景 | 推荐 | 理由 |
|
|
26
|
+
|------|------|------|
|
|
27
|
+
| 简单周期任务(日报、清理) | `@Scheduled` | 内置、无依赖 |
|
|
28
|
+
| 分布式/需重试/需监控 | **SnailJob** | 可视化管理、完整重试 |
|
|
29
|
+
| 广播(所有节点执行) | **SnailJob** | 支持广播模式 |
|
|
30
|
+
| 海量数据分片 | **SnailJob** | 静态分片/Map/MapReduce |
|
|
31
31
|
|
|
32
32
|
---
|
|
33
33
|
|
|
34
|
-
##
|
|
35
|
-
|
|
36
|
-
### 1.1 快速开始
|
|
37
|
-
|
|
38
|
-
```java
|
|
39
|
-
import org.springframework.scheduling.annotation.Scheduled;
|
|
40
|
-
import lombok.extern.slf4j.Slf4j;
|
|
41
|
-
|
|
42
|
-
@Slf4j
|
|
43
|
-
@Component
|
|
44
|
-
public class SimpleScheduledTask {
|
|
45
|
-
|
|
46
|
-
// ✅ 每天凌晨 2 点执行
|
|
47
|
-
@Scheduled(cron = "0 0 2 * * ?")
|
|
48
|
-
public void dailyCleanup() {
|
|
49
|
-
log.info("开始清理过期数据");
|
|
50
|
-
// 业务逻辑
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// ✅ 固定频率:每隔 60 秒执行
|
|
54
|
-
@Scheduled(fixedRate = 60000)
|
|
55
|
-
public void syncData() {
|
|
56
|
-
log.info("同步数据");
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// ✅ 固定延迟:上次执行结束后延迟 30 秒
|
|
60
|
-
@Scheduled(fixedDelay = 30000)
|
|
61
|
-
public void checkStatus() {
|
|
62
|
-
log.info("检查状态");
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// ✅ 初始延迟:启动 10 秒后才开始
|
|
66
|
-
@Scheduled(initialDelay = 10000, fixedRate = 60000)
|
|
67
|
-
public void reportStats() {
|
|
68
|
-
log.info("生成统计");
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
### 1.2 CRON 表达式
|
|
74
|
-
|
|
75
|
-
```
|
|
76
|
-
┌───────────── 秒 (0-59)
|
|
77
|
-
│ ┌───────────── 分钟 (0-59)
|
|
78
|
-
│ │ ┌───────────── 小时 (0-23)
|
|
79
|
-
│ │ │ ┌───────────── 日期 (1-31)
|
|
80
|
-
│ │ │ │ ┌───────────── 月份 (1-12)
|
|
81
|
-
│ │ │ │ │ ┌───────────── 星期 (0-7, 0和7都是周日)
|
|
82
|
-
* * * * * *
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
| 表达式 | 说明 |
|
|
86
|
-
|--------|------|
|
|
87
|
-
| `0 0 2 * * ?` | 每天 2:00 |
|
|
88
|
-
| `0 */5 * * * ?` | 每 5 分钟 |
|
|
89
|
-
| `0 0 */6 * * ?` | 每 6 小时 |
|
|
90
|
-
| `0 0 0 * * MON` | 每周一 0:00 |
|
|
91
|
-
| `0 0 0 1 * ?` | 每月 1 号 0:00 |
|
|
92
|
-
|
|
93
|
-
### 1.3 适用场景
|
|
94
|
-
|
|
95
|
-
- ✅ 任务数 < 100
|
|
96
|
-
- ✅ 简单逻辑、无需重试
|
|
97
|
-
- ✅ 单机执行即可
|
|
98
|
-
- ❌ 不适合:需要可视化管理、失败重试、分布式
|
|
99
|
-
|
|
100
|
-
---
|
|
101
|
-
|
|
102
|
-
## 二、SnailJob 方案(分布式场景)
|
|
103
|
-
|
|
104
|
-
> 源码位置:`ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/`
|
|
105
|
-
|
|
106
|
-
### 2.1 核心特性
|
|
107
|
-
|
|
108
|
-
| 特性 | 说明 |
|
|
109
|
-
|------|------|
|
|
110
|
-
| 可视化管理 | Web 界面管理任务 |
|
|
111
|
-
| 失败重试 | 多策略:指数退避、固定间隔 |
|
|
112
|
-
| 执行模式 | 集群、广播、静态分片、Map、MapReduce |
|
|
113
|
-
| 任务监控 | 实时日志、告警通知 |
|
|
114
|
-
| 工作流编排 | 可视化流程、决策节点 |
|
|
115
|
-
|
|
116
|
-
### 2.2 配置
|
|
34
|
+
## SnailJob 配置
|
|
117
35
|
|
|
118
36
|
```yaml
|
|
119
37
|
# application-dev.yml
|
|
@@ -128,23 +46,20 @@ snail-job:
|
|
|
128
46
|
port: 2${server.port}
|
|
129
47
|
```
|
|
130
48
|
|
|
131
|
-
### 2.3 启用配置
|
|
132
|
-
|
|
133
49
|
```java
|
|
134
|
-
//
|
|
50
|
+
// ruoyi-common/ruoyi-common-job/.../config/SnailJobConfig.java
|
|
135
51
|
@AutoConfiguration
|
|
136
52
|
@ConditionalOnProperty(prefix = "snail-job", name = "enabled", havingValue = "true")
|
|
137
53
|
@EnableScheduling
|
|
138
54
|
@EnableSnailJob
|
|
139
|
-
public class SnailJobConfig {
|
|
140
|
-
}
|
|
55
|
+
public class SnailJobConfig {}
|
|
141
56
|
```
|
|
142
57
|
|
|
143
58
|
---
|
|
144
59
|
|
|
145
|
-
##
|
|
60
|
+
## SnailJob 任务类型
|
|
146
61
|
|
|
147
|
-
###
|
|
62
|
+
### 基础任务(注解方式,推荐)
|
|
148
63
|
|
|
149
64
|
> 源码:`ruoyi-job/.../snailjob/TestAnnoJobExecutor.java`
|
|
150
65
|
|
|
@@ -159,361 +74,157 @@ import com.aizuda.snailjob.common.core.util.JsonUtil;
|
|
|
159
74
|
@JobExecutor(name = "testJobExecutor")
|
|
160
75
|
public class TestAnnoJobExecutor {
|
|
161
76
|
|
|
162
|
-
/**
|
|
163
|
-
* 任务执行方法
|
|
164
|
-
*
|
|
165
|
-
* @param jobArgs 任务参数(包含 jobParams、executorInfo 等)
|
|
166
|
-
* @return ExecuteResult 执行结果
|
|
167
|
-
*/
|
|
168
77
|
public ExecuteResult jobExecute(JobArgs jobArgs) {
|
|
169
|
-
// 本地日志(输出到控制台)
|
|
170
|
-
SnailJobLog.LOCAL.info("任务执行,参数: {}", JsonUtil.toJsonString(jobArgs));
|
|
171
|
-
|
|
172
|
-
// 远程日志(上报到 SnailJob 控制台)
|
|
173
78
|
SnailJobLog.REMOTE.info("任务执行,参数: {}", JsonUtil.toJsonString(jobArgs));
|
|
174
|
-
|
|
175
|
-
// 获取任务参数
|
|
176
79
|
String jobParams = jobArgs.getJobParams();
|
|
177
|
-
|
|
178
80
|
// 业务逻辑...
|
|
179
|
-
|
|
180
81
|
return ExecuteResult.success("执行成功");
|
|
181
82
|
}
|
|
182
83
|
}
|
|
183
84
|
```
|
|
184
85
|
|
|
185
|
-
###
|
|
186
|
-
|
|
187
|
-
> 源码:`ruoyi-job/.../snailjob/TestClassJobExecutor.java`
|
|
188
|
-
|
|
189
|
-
```java
|
|
190
|
-
import com.aizuda.snailjob.client.job.core.executor.AbstractJobExecutor;
|
|
191
|
-
import com.aizuda.snailjob.client.job.core.annotation.JobExecutor;
|
|
192
|
-
import com.aizuda.snailjob.client.job.core.dto.JobArgs;
|
|
193
|
-
import com.aizuda.snailjob.model.dto.ExecuteResult;
|
|
194
|
-
import com.aizuda.snailjob.common.log.SnailJobLog;
|
|
195
|
-
|
|
196
|
-
@Component
|
|
197
|
-
public class TestClassJobExecutor extends AbstractJobExecutor {
|
|
198
|
-
|
|
199
|
-
@Override
|
|
200
|
-
protected ExecuteResult doJobExecute(JobArgs jobArgs) {
|
|
201
|
-
SnailJobLog.REMOTE.info("类方式执行器,参数: {}", jobArgs.getJobParams());
|
|
202
|
-
return ExecuteResult.success("类方式执行成功");
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
```
|
|
206
|
-
|
|
207
|
-
### 3.3 广播任务
|
|
86
|
+
### 广播任务
|
|
208
87
|
|
|
209
88
|
> 源码:`ruoyi-job/.../snailjob/TestBroadcastJob.java`
|
|
210
89
|
|
|
211
|
-
|
|
90
|
+
所有节点都执行,适用于清理本地缓存等场景。
|
|
212
91
|
|
|
213
92
|
```java
|
|
214
|
-
import cn.hutool.core.util.RandomUtil;
|
|
215
|
-
import com.aizuda.snailjob.client.job.core.annotation.JobExecutor;
|
|
216
|
-
import com.aizuda.snailjob.client.job.core.dto.JobArgs;
|
|
217
|
-
import com.aizuda.snailjob.model.dto.ExecuteResult;
|
|
218
|
-
import com.aizuda.snailjob.common.log.SnailJobLog;
|
|
219
|
-
import org.springframework.beans.factory.annotation.Value;
|
|
220
|
-
|
|
221
|
-
@Slf4j
|
|
222
93
|
@Component
|
|
223
94
|
@JobExecutor(name = "testBroadcastJob")
|
|
224
95
|
public class TestBroadcastJob {
|
|
225
96
|
|
|
226
|
-
@Value("${snail-job.port}")
|
|
227
|
-
private int clientPort;
|
|
228
|
-
|
|
229
97
|
public ExecuteResult jobExecute(JobArgs jobArgs) {
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
if (randomInt < 50) {
|
|
234
|
-
// 抛出异常会触发重试
|
|
235
|
-
throw new RuntimeException("随机数小于50,任务失败");
|
|
236
|
-
}
|
|
237
|
-
|
|
98
|
+
SnailJobLog.REMOTE.info("广播任务执行");
|
|
99
|
+
// 每个节点都会执行此方法
|
|
238
100
|
return ExecuteResult.success("广播任务执行成功");
|
|
239
101
|
}
|
|
240
102
|
}
|
|
241
103
|
```
|
|
242
104
|
|
|
243
|
-
###
|
|
105
|
+
### 静态分片任务
|
|
244
106
|
|
|
245
107
|
> 源码:`ruoyi-job/.../snailjob/TestStaticShardingJob.java`
|
|
246
108
|
|
|
247
|
-
|
|
109
|
+
按固定规则分片,每个节点处理不同数据范围。
|
|
248
110
|
|
|
249
111
|
```java
|
|
250
|
-
import cn.hutool.core.convert.Convert;
|
|
251
|
-
import com.aizuda.snailjob.client.job.core.annotation.JobExecutor;
|
|
252
|
-
import com.aizuda.snailjob.client.job.core.dto.JobArgs;
|
|
253
|
-
import com.aizuda.snailjob.model.dto.ExecuteResult;
|
|
254
|
-
import com.aizuda.snailjob.common.log.SnailJobLog;
|
|
255
|
-
|
|
256
112
|
@Component
|
|
257
113
|
@JobExecutor(name = "testStaticShardingJob")
|
|
258
114
|
public class TestStaticShardingJob {
|
|
259
115
|
|
|
260
|
-
|
|
261
|
-
* 静态分片任务
|
|
262
|
-
* jobParams 格式:起始ID,结束ID(如:1,100000)
|
|
263
|
-
*/
|
|
116
|
+
// jobParams 格式:起始ID,结束ID(如:1,100000)
|
|
264
117
|
public ExecuteResult jobExecute(JobArgs jobArgs) {
|
|
265
|
-
String
|
|
266
|
-
SnailJobLog.LOCAL.info("开始执行分片任务,参数: {}", jobParams);
|
|
267
|
-
|
|
268
|
-
// 解析分片参数
|
|
269
|
-
String[] split = jobParams.split(",");
|
|
118
|
+
String[] split = jobArgs.getJobParams().split(",");
|
|
270
119
|
Long fromId = Long.parseLong(split[0]);
|
|
271
120
|
Long toId = Long.parseLong(split[1]);
|
|
272
|
-
|
|
273
121
|
SnailJobLog.REMOTE.info("处理 ID 范围: {} - {}", fromId, toId);
|
|
274
|
-
|
|
275
|
-
// 业务逻辑:处理该范围的数据
|
|
276
|
-
// processDataRange(fromId, toId);
|
|
277
|
-
|
|
122
|
+
// 处理该范围的数据
|
|
278
123
|
return ExecuteResult.success("分片任务完成");
|
|
279
124
|
}
|
|
280
125
|
}
|
|
281
126
|
```
|
|
282
127
|
|
|
283
|
-
|
|
284
|
-
1. 任务类型选择"静态分片"
|
|
285
|
-
2. 分片参数设置多组(每组对应一个分片):
|
|
286
|
-
- 分片 0:`1,100000`
|
|
287
|
-
- 分片 1:`100001,200000`
|
|
288
|
-
- 分片 2:`200001,300000`
|
|
128
|
+
**控制台分片配置**:分片0=`1,100000` / 分片1=`100001,200000` / 分片2=`200001,300000`
|
|
289
129
|
|
|
290
|
-
###
|
|
130
|
+
### Map 任务(动态分片)
|
|
291
131
|
|
|
292
132
|
> 源码:`ruoyi-job/.../snailjob/TestMapJobAnnotation.java`
|
|
293
133
|
|
|
294
|
-
|
|
134
|
+
运行时动态拆分数据,并行执行。
|
|
295
135
|
|
|
296
136
|
```java
|
|
297
|
-
import com.aizuda.snailjob.client.job.core.annotation.JobExecutor;
|
|
298
137
|
import com.aizuda.snailjob.client.job.core.annotation.MapExecutor;
|
|
299
138
|
import com.aizuda.snailjob.client.job.core.dto.MapArgs;
|
|
300
139
|
import com.aizuda.snailjob.client.job.core.MapHandler;
|
|
301
|
-
import com.aizuda.snailjob.model.dto.ExecuteResult;
|
|
302
|
-
import com.aizuda.snailjob.common.log.SnailJobLog;
|
|
303
|
-
|
|
304
|
-
import java.util.List;
|
|
305
|
-
import java.util.stream.Collectors;
|
|
306
|
-
import java.util.stream.IntStream;
|
|
307
140
|
|
|
308
141
|
@Component
|
|
309
142
|
@JobExecutor(name = "testMapJobAnnotation")
|
|
310
143
|
public class TestMapJobAnnotation {
|
|
311
144
|
|
|
312
|
-
|
|
313
|
-
* Map 入口:拆分数据
|
|
314
|
-
* 无 taskName 的 @MapExecutor 是入口方法
|
|
315
|
-
*/
|
|
316
|
-
@MapExecutor
|
|
145
|
+
@MapExecutor // 无 taskName = 入口方法
|
|
317
146
|
public ExecuteResult doJobMapExecute(MapArgs mapArgs, MapHandler mapHandler) {
|
|
318
|
-
SnailJobLog.REMOTE.info("Map 入口执行");
|
|
319
|
-
|
|
320
|
-
// 将 1-200 按每组 50 个分成 4 组
|
|
321
147
|
List<List<Integer>> partition = IntStream.rangeClosed(1, 200)
|
|
322
148
|
.boxed()
|
|
323
149
|
.collect(Collectors.groupingBy(i -> (i - 1) / 50))
|
|
324
|
-
.values()
|
|
325
|
-
.stream()
|
|
326
|
-
.toList();
|
|
327
|
-
|
|
328
|
-
// 分发到子任务 doCalc
|
|
150
|
+
.values().stream().toList();
|
|
329
151
|
return mapHandler.doMap(partition, "doCalc");
|
|
330
152
|
}
|
|
331
153
|
|
|
332
|
-
|
|
333
|
-
* Map 子任务:处理每个分片
|
|
334
|
-
*/
|
|
335
|
-
@MapExecutor(taskName = "doCalc")
|
|
154
|
+
@MapExecutor(taskName = "doCalc") // 子任务
|
|
336
155
|
public ExecuteResult doCalc(MapArgs mapArgs) {
|
|
337
|
-
// 获取当前分片的数据
|
|
338
156
|
List<Integer> sourceList = (List<Integer>) mapArgs.getMapResult();
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
// 计算当前分片的总和
|
|
343
|
-
int partitionTotal = sourceList.stream().mapToInt(i -> i).sum();
|
|
344
|
-
|
|
345
|
-
return ExecuteResult.success(partitionTotal);
|
|
157
|
+
int total = sourceList.stream().mapToInt(i -> i).sum();
|
|
158
|
+
return ExecuteResult.success(total);
|
|
346
159
|
}
|
|
347
160
|
}
|
|
348
161
|
```
|
|
349
162
|
|
|
350
|
-
###
|
|
163
|
+
### MapReduce 任务(分片 + 汇总)
|
|
351
164
|
|
|
352
165
|
> 源码:`ruoyi-job/.../snailjob/TestMapReduceAnnotation1.java`
|
|
353
166
|
|
|
354
|
-
|
|
167
|
+
在 Map 基础上增加 Reduce 汇总。
|
|
355
168
|
|
|
356
169
|
```java
|
|
357
|
-
import com.aizuda.snailjob.client.job.core.annotation.JobExecutor;
|
|
358
|
-
import com.aizuda.snailjob.client.job.core.annotation.MapExecutor;
|
|
359
170
|
import com.aizuda.snailjob.client.job.core.annotation.ReduceExecutor;
|
|
360
|
-
import com.aizuda.snailjob.client.job.core.dto.MapArgs;
|
|
361
171
|
import com.aizuda.snailjob.client.job.core.dto.ReduceArgs;
|
|
362
|
-
import com.aizuda.snailjob.client.job.core.MapHandler;
|
|
363
|
-
import com.aizuda.snailjob.model.dto.ExecuteResult;
|
|
364
|
-
import com.aizuda.snailjob.common.log.SnailJobLog;
|
|
365
|
-
|
|
366
|
-
import java.util.List;
|
|
367
|
-
import java.util.stream.Collectors;
|
|
368
|
-
import java.util.stream.IntStream;
|
|
369
172
|
|
|
370
173
|
@Component
|
|
371
174
|
@JobExecutor(name = "testMapReduceAnnotation1")
|
|
372
175
|
public class TestMapReduceAnnotation1 {
|
|
373
176
|
|
|
374
|
-
/**
|
|
375
|
-
* Map 入口:拆分数据
|
|
376
|
-
*/
|
|
377
177
|
@MapExecutor
|
|
378
178
|
public ExecuteResult rootMapExecute(MapArgs mapArgs, MapHandler mapHandler) {
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
// 将 1-200 按每组 50 个分成 4 组
|
|
382
|
-
List<List<Integer>> partition = IntStream.rangeClosed(1, 200)
|
|
383
|
-
.boxed()
|
|
384
|
-
.collect(Collectors.groupingBy(i -> (i - 1) / 50))
|
|
385
|
-
.values()
|
|
386
|
-
.stream()
|
|
387
|
-
.toList();
|
|
388
|
-
|
|
179
|
+
// 拆分数据(同 Map 任务)
|
|
389
180
|
return mapHandler.doMap(partition, "doCalc");
|
|
390
181
|
}
|
|
391
182
|
|
|
392
|
-
/**
|
|
393
|
-
* Map 子任务:计算每个分片的总和
|
|
394
|
-
*/
|
|
395
183
|
@MapExecutor(taskName = "doCalc")
|
|
396
184
|
public ExecuteResult doCalc(MapArgs mapArgs) {
|
|
397
185
|
List<Integer> sourceList = (List<Integer>) mapArgs.getMapResult();
|
|
398
|
-
|
|
399
|
-
int partitionTotal = sourceList.stream().mapToInt(i -> i).sum();
|
|
400
|
-
|
|
401
|
-
SnailJobLog.REMOTE.info("分片计算完成,总和: {}", partitionTotal);
|
|
402
|
-
|
|
403
|
-
return ExecuteResult.success(partitionTotal);
|
|
186
|
+
return ExecuteResult.success(sourceList.stream().mapToInt(i -> i).sum());
|
|
404
187
|
}
|
|
405
188
|
|
|
406
|
-
/**
|
|
407
|
-
* Reduce 汇总:合并所有分片结果
|
|
408
|
-
*/
|
|
409
189
|
@ReduceExecutor
|
|
410
190
|
public ExecuteResult reduceExecute(ReduceArgs reduceArgs) {
|
|
411
|
-
// 获取所有 Map 子任务的结果
|
|
412
191
|
List<?> mapResults = reduceArgs.getMapResult();
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
SnailJobLog.REMOTE.info("Reduce 汇总完成,最终总和: {}", reduceTotal);
|
|
419
|
-
|
|
420
|
-
return ExecuteResult.success(reduceTotal);
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
```
|
|
424
|
-
|
|
425
|
-
---
|
|
426
|
-
|
|
427
|
-
## 四、SnailJob 日志工具
|
|
428
|
-
|
|
429
|
-
### 4.1 日志类型
|
|
430
|
-
|
|
431
|
-
```java
|
|
432
|
-
import com.aizuda.snailjob.common.log.SnailJobLog;
|
|
433
|
-
|
|
434
|
-
// 本地日志(输出到控制台/日志文件)
|
|
435
|
-
SnailJobLog.LOCAL.info("本地日志: {}", message);
|
|
436
|
-
SnailJobLog.LOCAL.warn("警告: {}", message);
|
|
437
|
-
SnailJobLog.LOCAL.error("错误: {}", message, exception);
|
|
438
|
-
|
|
439
|
-
// 远程日志(上报到 SnailJob 控制台,可在 Web 界面查看)
|
|
440
|
-
SnailJobLog.REMOTE.info("远程日志: {}", message);
|
|
441
|
-
SnailJobLog.REMOTE.warn("警告: {}", message);
|
|
442
|
-
SnailJobLog.REMOTE.error("错误: {}", message, exception);
|
|
443
|
-
```
|
|
444
|
-
|
|
445
|
-
### 4.2 日志最佳实践
|
|
446
|
-
|
|
447
|
-
```java
|
|
448
|
-
@Component
|
|
449
|
-
@JobExecutor(name = "orderProcessJob")
|
|
450
|
-
public class OrderProcessJob {
|
|
451
|
-
|
|
452
|
-
public ExecuteResult jobExecute(JobArgs jobArgs) {
|
|
453
|
-
String jobParams = jobArgs.getJobParams();
|
|
454
|
-
|
|
455
|
-
// 1. 记录任务开始
|
|
456
|
-
SnailJobLog.REMOTE.info("开始处理订单,参数: {}", jobParams);
|
|
457
|
-
|
|
458
|
-
try {
|
|
459
|
-
// 2. 业务逻辑
|
|
460
|
-
int count = processOrders(jobParams);
|
|
461
|
-
|
|
462
|
-
// 3. 记录成功
|
|
463
|
-
SnailJobLog.REMOTE.info("订单处理完成,处理数量: {}", count);
|
|
464
|
-
return ExecuteResult.success("处理 " + count + " 条订单");
|
|
465
|
-
|
|
466
|
-
} catch (Exception e) {
|
|
467
|
-
// 4. 记录失败(同时记录本地和远程)
|
|
468
|
-
SnailJobLog.LOCAL.error("订单处理失败", e);
|
|
469
|
-
SnailJobLog.REMOTE.error("订单处理失败: {}", e.getMessage());
|
|
470
|
-
|
|
471
|
-
// 抛出异常触发重试
|
|
472
|
-
throw e;
|
|
473
|
-
}
|
|
192
|
+
int total = mapResults.stream()
|
|
193
|
+
.mapToInt(i -> Integer.parseInt((String) i)).sum();
|
|
194
|
+
SnailJobLog.REMOTE.info("Reduce 汇总,最终总和: {}", total);
|
|
195
|
+
return ExecuteResult.success(total);
|
|
474
196
|
}
|
|
475
197
|
}
|
|
476
198
|
```
|
|
477
199
|
|
|
478
200
|
---
|
|
479
201
|
|
|
480
|
-
##
|
|
202
|
+
## 执行模式对比
|
|
481
203
|
|
|
482
204
|
| 模式 | 特点 | 适用场景 |
|
|
483
205
|
|------|------|---------|
|
|
484
206
|
| **集群** | 多节点竞争,只有一个执行 | 订单处理、数据汇总 |
|
|
485
207
|
| **广播** | 所有节点都执行 | 清理缓存、刷新配置 |
|
|
486
208
|
| **静态分片** | 按固定规则分片 | 已知数据范围的批处理 |
|
|
487
|
-
| **Map** | 动态分片 |
|
|
209
|
+
| **Map** | 动态分片 | 运行时确定分片 |
|
|
488
210
|
| **MapReduce** | 动态分片 + 结果汇总 | 分布式计算(求和、统计) |
|
|
489
211
|
|
|
490
212
|
---
|
|
491
213
|
|
|
492
|
-
##
|
|
493
|
-
|
|
494
|
-
### 6.1 创建任务
|
|
214
|
+
## 日志工具
|
|
495
215
|
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
3. 配置项:
|
|
499
|
-
- 任务名称:`testJobExecutor`(与 `@JobExecutor(name)` 一致)
|
|
500
|
-
- 任务类型:集群/广播/静态分片/Map/MapReduce
|
|
501
|
-
- 触发类型:CRON / 固定频率
|
|
502
|
-
- CRON 表达式:`0 0 2 * * ?`
|
|
503
|
-
|
|
504
|
-
### 6.2 重试策略
|
|
216
|
+
```java
|
|
217
|
+
import com.aizuda.snailjob.common.log.SnailJobLog;
|
|
505
218
|
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
| 指数退避 | 间隔逐倍增加 | 服务恢复中 |
|
|
510
|
-
| CRON | 按表达式重试 | 定点重试 |
|
|
219
|
+
SnailJobLog.LOCAL.info("本地日志: {}", msg); // 输出到控制台/日志文件
|
|
220
|
+
SnailJobLog.REMOTE.info("远程日志: {}", msg); // 上报到 SnailJob 控制台
|
|
221
|
+
```
|
|
511
222
|
|
|
512
223
|
---
|
|
513
224
|
|
|
514
|
-
##
|
|
225
|
+
## 最佳实践
|
|
515
226
|
|
|
516
|
-
###
|
|
227
|
+
### 标准任务模板
|
|
517
228
|
|
|
518
229
|
```java
|
|
519
230
|
@Component
|
|
@@ -525,19 +236,12 @@ public class OrderCleanupJob {
|
|
|
525
236
|
|
|
526
237
|
public ExecuteResult jobExecute(JobArgs jobArgs) {
|
|
527
238
|
SnailJobLog.REMOTE.info("开始清理过期订单");
|
|
528
|
-
|
|
529
239
|
try {
|
|
530
|
-
// 1. 解析参数
|
|
531
240
|
String params = jobArgs.getJobParams();
|
|
532
241
|
int days = StringUtils.isBlank(params) ? 30 : Integer.parseInt(params);
|
|
533
|
-
|
|
534
|
-
// 2. 执行业务
|
|
535
242
|
int count = orderService.cleanupExpiredOrders(days);
|
|
536
|
-
|
|
537
|
-
// 3. 返回成功
|
|
538
|
-
SnailJobLog.REMOTE.info("清理完成,删除 {} 条订单", count);
|
|
243
|
+
SnailJobLog.REMOTE.info("清理完成,删除 {} 条", count);
|
|
539
244
|
return ExecuteResult.success("清理 " + count + " 条");
|
|
540
|
-
|
|
541
245
|
} catch (Exception e) {
|
|
542
246
|
SnailJobLog.REMOTE.error("清理失败: {}", e.getMessage());
|
|
543
247
|
throw e; // 抛出异常触发重试
|
|
@@ -546,88 +250,65 @@ public class OrderCleanupJob {
|
|
|
546
250
|
}
|
|
547
251
|
```
|
|
548
252
|
|
|
549
|
-
###
|
|
253
|
+
### 幂等性保证
|
|
550
254
|
|
|
551
255
|
```java
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
public ExecuteResult jobExecute(JobArgs jobArgs) {
|
|
557
|
-
String orderId = jobArgs.getJobParams();
|
|
558
|
-
|
|
559
|
-
// 1. 幂等检查
|
|
560
|
-
if (paymentService.isSynced(orderId)) {
|
|
561
|
-
SnailJobLog.REMOTE.info("订单 {} 已同步,跳过", orderId);
|
|
562
|
-
return ExecuteResult.success("已同步");
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
// 2. 执行同步
|
|
566
|
-
paymentService.sync(orderId);
|
|
567
|
-
|
|
568
|
-
return ExecuteResult.success("同步成功");
|
|
256
|
+
public ExecuteResult jobExecute(JobArgs jobArgs) {
|
|
257
|
+
String orderId = jobArgs.getJobParams();
|
|
258
|
+
if (paymentService.isSynced(orderId)) {
|
|
259
|
+
return ExecuteResult.success("已同步,跳过");
|
|
569
260
|
}
|
|
261
|
+
paymentService.sync(orderId);
|
|
262
|
+
return ExecuteResult.success("同步成功");
|
|
570
263
|
}
|
|
571
264
|
```
|
|
572
265
|
|
|
573
|
-
###
|
|
266
|
+
### 错误处理
|
|
574
267
|
|
|
575
268
|
```java
|
|
576
|
-
//
|
|
577
|
-
|
|
578
|
-
try {
|
|
579
|
-
// 业务逻辑
|
|
580
|
-
} catch (Exception e) {
|
|
581
|
-
SnailJobLog.REMOTE.error("执行失败", e);
|
|
582
|
-
throw e; // ✅ 抛出异常,SnailJob 会自动重试
|
|
583
|
-
}
|
|
584
|
-
}
|
|
269
|
+
// 抛出异常 -> SnailJob 自动重试
|
|
270
|
+
throw e;
|
|
585
271
|
|
|
586
|
-
//
|
|
587
|
-
|
|
588
|
-
try {
|
|
589
|
-
// 业务逻辑
|
|
590
|
-
} catch (Exception e) {
|
|
591
|
-
SnailJobLog.REMOTE.error("执行失败", e);
|
|
592
|
-
return ExecuteResult.failure("失败"); // ❌ 不会触发重试
|
|
593
|
-
}
|
|
594
|
-
}
|
|
272
|
+
// 返回 failure -> 不会触发重试(慎用)
|
|
273
|
+
return ExecuteResult.failure("失败");
|
|
595
274
|
```
|
|
596
275
|
|
|
597
276
|
---
|
|
598
277
|
|
|
599
|
-
##
|
|
278
|
+
## 控制台配置
|
|
600
279
|
|
|
601
|
-
|
|
280
|
+
1. **任务管理** -> **新增任务**
|
|
281
|
+
2. 任务名称与 `@JobExecutor(name)` 一致
|
|
282
|
+
3. 任务类型:集群/广播/静态分片/Map/MapReduce
|
|
283
|
+
4. 触发类型:CRON / 固定频率
|
|
602
284
|
|
|
603
|
-
|
|
604
|
-
2. 检查 `@JobExecutor(name)` 与控制台配置一致
|
|
605
|
-
3. 检查 SnailJob 服务是否启动
|
|
606
|
-
4. 查看日志是否有连接错误
|
|
285
|
+
### 重试策略
|
|
607
286
|
|
|
608
|
-
|
|
287
|
+
| 策略 | 说明 | 场景 |
|
|
288
|
+
|------|------|------|
|
|
289
|
+
| 固定间隔 | 每次间隔相同 | 网络抖动 |
|
|
290
|
+
| 指数退避 | 间隔逐倍增加 | 服务恢复中 |
|
|
291
|
+
| CRON | 按表达式重试 | 定点重试 |
|
|
609
292
|
|
|
610
|
-
|
|
611
|
-
|------|------|
|
|
612
|
-
| 任务 < 100,简单逻辑 | `@Scheduled` |
|
|
613
|
-
| 需要重试、监控 | SnailJob |
|
|
614
|
-
| 分布式部署 | SnailJob |
|
|
615
|
-
| 需要 Web 管理 | SnailJob |
|
|
293
|
+
---
|
|
616
294
|
|
|
617
|
-
|
|
295
|
+
## 常见问题
|
|
618
296
|
|
|
619
|
-
|
|
620
|
-
|
|
297
|
+
| 问题 | 排查步骤 |
|
|
298
|
+
|------|---------|
|
|
299
|
+
| 任务不执行 | 1.检查 `snail-job.enabled: true` 2.`@JobExecutor(name)` 与控制台一致 3.SnailJob 服务是否启动 |
|
|
300
|
+
| @Scheduled vs SnailJob | 简单/<100个任务 -> @Scheduled;需重试/监控/分布式 -> SnailJob |
|
|
301
|
+
| 查看任务日志 | 本地 -> 应用日志;远程 -> SnailJob 控制台 -> 任务实例 -> 查看日志 |
|
|
621
302
|
|
|
622
303
|
---
|
|
623
304
|
|
|
624
|
-
##
|
|
305
|
+
## 核心文件位置
|
|
625
306
|
|
|
626
307
|
| 文件 | 路径 |
|
|
627
308
|
|------|------|
|
|
628
|
-
|
|
|
629
|
-
|
|
|
630
|
-
|
|
|
631
|
-
|
|
|
632
|
-
| Map
|
|
633
|
-
| MapReduce
|
|
309
|
+
| 注解方式 | `ruoyi-modules/ruoyi-job/.../snailjob/TestAnnoJobExecutor.java` |
|
|
310
|
+
| 类方式 | `ruoyi-modules/ruoyi-job/.../snailjob/TestClassJobExecutor.java` |
|
|
311
|
+
| 广播任务 | `ruoyi-modules/ruoyi-job/.../snailjob/TestBroadcastJob.java` |
|
|
312
|
+
| 静态分片 | `ruoyi-modules/ruoyi-job/.../snailjob/TestStaticShardingJob.java` |
|
|
313
|
+
| Map 任务 | `ruoyi-modules/ruoyi-job/.../snailjob/TestMapJobAnnotation.java` |
|
|
314
|
+
| MapReduce | `ruoyi-modules/ruoyi-job/.../snailjob/TestMapReduceAnnotation1.java` |
|