@microi.net/cli 5.8.5 → 5.8.6
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/.codebuddy-plugin/marketplace.json +2 -2
- package/.codebuddy-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/.mcp.json +1 -1
- package/.workbuddy-plugin/marketplace.json +2 -2
- package/.workbuddy-plugin/plugin.json +1 -1
- package/LICENSE +21 -21
- package/README.md +71 -71
- package/assets/build-meta.json +6 -6
- package/assets/feature-matrix.json +138 -138
- package/assets/logo.svg +4 -4
- package/cordis.patch.yml +1 -1
- package/package.json +1 -1
- package/scripts/codex-marketplace.json +20 -20
- package/scripts/mcp-codex-stdio-adapter.js +189 -189
- package/scripts/mcp-trae-windows-launcher.cmd +21 -21
- package/scripts/microi-cli-mcp.js +7 -7
- package/scripts/microi-cli.js +66 -65
- package/scripts/microi-codex-broker.js +450 -450
- package/scripts/microi-codex-router.js +618 -618
- package/scripts/microi-skills.meta.json +384 -384
- package/skills/.microi-skills-version.json +2 -2
- package/skills/.progressive-disclosure-manifest.json +3566 -3566
- package/skills/README.md +287 -287
- package/skills/ai-engine/SKILL.md +269 -265
- package/skills/ai-engine/agents/openai.yaml +4 -4
- package/skills/ai-engine/references/ai-employees.md +48 -48
- package/skills/ai-engine/references/self-hosted-digital-human.md +59 -59
- package/skills/ai-platform-governance/SKILL.md +177 -177
- package/skills/ai-platform-governance/references/progressive-01-/345/212/237/350/203/275/345/274/200/345/205/263.md +190 -190
- package/skills/app-store/SKILL.md +525 -525
- package/skills/app-store/agents/openai.yaml +4 -4
- package/skills/business-blueprint/SKILL.md +193 -193
- package/skills/datasource-engine/SKILL.md +93 -93
- package/skills/datasource-engine/agents/openai.yaml +4 -4
- package/skills/dos-orm/SKILL.md +97 -97
- package/skills/dos-orm/references/api-reference.md +229 -229
- package/skills/email-engine/SKILL.md +81 -81
- package/skills/email-engine/references/v8-email.md +34 -34
- package/skills/job-engine/SKILL.md +176 -176
- package/skills/job-engine/agents/openai.yaml +4 -4
- package/skills/message-notification/SKILL.md +156 -156
- package/skills/message-notification/agents/openai.yaml +5 -5
- package/skills/message-notification/references/contracts.md +102 -102
- package/skills/microi/SKILL.md +14 -14
- package/skills/microi-ai-app-auth.js +652 -652
- package/skills/microi-ai-application/SKILL.md +115 -115
- package/skills/microi-ai-application/agents/openai.yaml +4 -4
- package/skills/microi-ai-application/references/frontend-baseline.md +164 -164
- package/skills/microi-client-frontend/SKILL.md +244 -244
- package/skills/microi-client-frontend/references/progressive-01-3-/345/212/250/346/200/201/346/214/211/351/222/256/347/263/273/347/273/237.md +144 -144
- package/skills/microi-client-frontend/references/progressive-02-8-/350/277/220/350/241/214/346/227/266/351/253/230/351/242/221/345/235/221/345/244/215/347/233/230.md +196 -196
- package/skills/microi-client-frontend/references/progressive-03-vue3-/345/211/215/347/253/257/345/276/256/346/234/215/345/212/241/345/256/277/344/270/273/350/247/204/345/210/231.md +167 -167
- package/skills/microi-codex/SKILL.md +102 -102
- package/skills/microi-codex-installer/SKILL.md +231 -231
- package/skills/microi-codex-installer/agents/openai.yaml +7 -7
- package/skills/microi-datasource-mapping/SKILL.md +122 -122
- package/skills/microi-db-schema/SKILL.md +175 -175
- package/skills/microi-db-schema/agents/openai.yaml +4 -4
- package/skills/microi-db-schema/references/core-tables.md +695 -695
- package/skills/microi-db-schema/references/form-component-options.md +256 -256
- package/skills/microi-db-schema/references/schema-overview.md +202 -202
- package/skills/microi-db-schema/references/schema.md +646 -646
- package/skills/microi-db-schema/references/table-catalog.md +1599 -1599
- package/skills/microi-deployment/SKILL.md +221 -221
- package/skills/microi-deployment/references/deployment-matrix.md +109 -109
- package/skills/microi-docs-coverage/SKILL.md +133 -133
- package/skills/microi-docs-coverage/references/capability-map.md +91 -91
- package/skills/microi-docs-coverage/scripts/audit-doc-skill-coverage.mjs +894 -894
- package/skills/microi-form-engine/SKILL.md +333 -333
- package/skills/microi-form-engine/references/component-catalog.md +218 -218
- package/skills/microi-form-engine/references/data-source-events.md +124 -124
- package/skills/microi-form-layout/SKILL.md +205 -205
- package/skills/microi-form-layout/references/progressive-01-3-/344/270/211/347/247/215/345/210/206/347/273/204/347/232/204/345/255/230/345/202/250/344/270/216/351/205/215/347/275/256.md +235 -235
- package/skills/microi-frontend-sdk/SKILL.md +194 -194
- package/skills/microi-frontend-sdk/references/progressive-01-token-/345/275/223/345/211/215/347/231/273/345/275/225/347/224/250/346/210/267/344/270/216/345/275/223/345/211/215/347/273/210/347/253/257/347/231/273/345/275/225/345/215/217/350/256/256.md +176 -176
- package/skills/microi-left-right-layout/SKILL.md +141 -141
- package/skills/microi-microservice/SKILL.md +326 -324
- package/skills/microi-microservice/references/runtime-delivery.md +278 -278
- package/skills/microi-mobile-app-quality/SKILL.md +185 -185
- package/skills/microi-mobile-app-quality/references/progressive-01-4-/351/207/215/350/246/201/346/214/211/351/222/256/345/277/205/351/241/273/345/270/246/345/233/276/346/240/207.md +213 -213
- package/skills/microi-mobile-app-quality/references/progressive-02-9-/344/270/273/351/242/230/345/210/207/346/215/242/345/277/205/351/241/273/347/234/237/345/256/236/344/270/224/345/205/250/345/261/200/347/224/237/346/225/210.md +128 -128
- package/skills/microi-solution-quotation/SKILL.md +78 -78
- package/skills/microi-solution-quotation/agents/openai.yaml +4 -4
- package/skills/microi-solution-quotation/scripts/build_solution_quote.py +296 -296
- package/skills/microi-sso/SKILL.md +92 -92
- package/skills/microi-sso/references/acceptance.md +49 -49
- package/skills/microi-sso/references/configuration-and-security.md +53 -53
- package/skills/microi-sso/references/inbound.md +53 -53
- package/skills/microi-sso/references/outbound.md +39 -39
- package/skills/microi-system-delivery/SKILL.md +137 -137
- package/skills/microi-system-delivery/references/progressive-01-/346/240/207/345/207/206/345/267/245/344/275/234/346/265/201.md +193 -193
- package/skills/microi-system-delivery/references/progressive-02-/350/207/252/345/212/250/345/214/226/346/265/213/350/257/225/345/277/205/351/241/273/350/246/206/347/233/226/347/232/204/345/235/221.md +217 -217
- package/skills/microi-ui/SKILL.md +192 -192
- package/skills/microi-ui/references/progressive-01-/347/247/273/345/212/250/347/253/257/345/234/272/346/231/257/350/223/235/345/233/276.md +183 -183
- package/skills/microi-uniapp-frontend/SKILL.md +193 -193
- package/skills/microi-uniapp-frontend/references/progressive-01-/347/247/273/345/212/250/347/253/257/345/210/206/347/261/273-/345/217/214/346/240/217/345/210/227/350/241/250/347/213/254/347/253/213/346/273/232/345/212/250.md +225 -225
- package/skills/microi-uniapp-frontend/references/progressive-02-/345/205/263/351/224/256/344/270/232/345/212/241/350/265/204/344/272/247/344/270/215/345/276/227/351/273/230/350/256/244/351/200/211/344/270/255.md +154 -154
- package/skills/microi.v8.js +1921 -1921
- package/skills/module-engine/SKILL.md +255 -255
- package/skills/module-engine/references/module-config.md +204 -204
- package/skills/ocr-engine/SKILL.md +113 -113
- package/skills/ocr-engine/agents/openai.yaml +4 -4
- package/skills/page-engine/SKILL.md +206 -206
- package/skills/page-engine/examples/compact-dashboard.json +1444 -1444
- package/skills/page-engine/references/progressive-01-/346/211/200/346/234/211/347/273/204/344/273/266/347/261/273/345/236/213.md +234 -234
- package/skills/page-engine/references/progressive-02-/347/211/210/346/234/254/345/216/206/345/217/262-/345/271/266/345/217/221/344/277/235/345/255/230/344/270/216/345/233/236/346/273/232.md +60 -60
- package/skills/performance-testing/SKILL.md +221 -221
- package/skills/playwright-e2e/SKILL.md +196 -196
- package/skills/playwright-e2e/references/progressive-01-/345/205/250/350/207/252/345/212/250/347/231/273/345/275/225-/345/205/215/351/252/214/350/257/201/347/240/201-/344/275/206/344/270/215/345/205/215/345/257/206/347/240/201-/345/277/205/350/257/273.md +173 -173
- package/skills/playwright-e2e/references/progressive-02-/346/226/207/345/255/227/345/257/271/346/257/224/345/272/246/344/270/216/345/217/257/350/257/273/346/200/247/350/207/252/345/212/250/345/214/226/346/243/200/346/237/245-/345/277/205/345/201/232.md +183 -183
- package/skills/playwright-e2e/references/progressive-03-microi-helper-/346/250/241/346/235/277.md +221 -221
- package/skills/playwright-e2e/references/progressive-04-ci-/345/273/272/350/256/256.md +115 -115
- package/skills/print-engine/SKILL.md +259 -259
- package/skills/production-readonly-audit/SKILL.md +41 -41
- package/skills/report-engine/SKILL.md +71 -71
- package/skills/report-engine/agents/openai.yaml +4 -4
- package/skills/scripts/optimize-progressive-disclosure.mjs +204 -204
- package/skills/scripts/refresh-progressive-disclosure.mjs +64 -64
- package/skills/scripts/sync-embedded-skills.mjs +46 -46
- package/skills/scripts/validate-progressive-disclosure.mjs +57 -57
- package/skills/search-engine/SKILL.md +75 -75
- package/skills/search-engine/agents/openai.yaml +4 -4
- package/skills/spider-engine/SKILL.md +190 -190
- package/skills/system-observability/SKILL.md +248 -248
- package/skills/system-observability/references/memory-incident-triage.md +77 -77
- package/skills/translate-engine/SKILL.md +140 -140
- package/skills/translate-engine/agents/openai.yaml +4 -4
- package/skills/ui-design/SKILL.md +223 -223
- package/skills/ui-design/assets/pattern-showcase/app.js +54 -54
- package/skills/ui-design/assets/pattern-showcase/index.html +163 -163
- package/skills/ui-design/assets/pattern-showcase/styles.css +311 -311
- package/skills/ui-design/assets/templates/MCI-DESIGN.md +206 -206
- package/skills/ui-design/references/design-pattern-library.md +184 -184
- package/skills/ui-design/references/mci-design-contract.md +163 -163
- package/skills/ui-design/references/motion-and-media.md +78 -78
- package/skills/ui-design/references/product-flow-recipes.md +94 -94
- package/skills/ui-design/references/progressive-01-/351/242/234/350/211/262/344/275/223/347/263/273-css-variables-/346/224/257/346/214/201/344/270/273/351/242/230/345/210/207/346/215/242.md +218 -218
- package/skills/ui-design/references/progressive-02-/345/255/227/344/275/223.md +164 -164
- package/skills/ui-design/references/progressive-03-/345/212/250/346/225/210/350/247/204/350/214/203-/344/270/260/345/257/214/344/275/206/344/270/215/345/215/241.md +235 -235
- package/skills/ui-design/references/progressive-04-/347/273/204/344/273/266/351/243/216/346/240/274/351/200/237/346/237/245.md +152 -152
- package/skills/ui-design/references/progressive-05-/347/247/273/345/212/250/347/253/257/344/270/223/347/224/250/350/247/204/350/214/203.md +238 -238
- package/skills/ui-design/references/progressive-06-/344/270/273/351/242/230/345/210/207/346/215/242/345/256/236/347/216/260.md +194 -194
- package/skills/ui-design/references/progressive-07-/351/200/237/346/237/245-/344/273/216/345/244/264/346/220/255/345/273/272/344/270/200/344/270/252/347/247/273/345/212/250/347/253/257/351/241/265/351/235/242.md +207 -207
- package/skills/ui-design/references/progressive-08-/350/241/250/345/215/225/345/210/206/347/273/204/350/247/204/350/214/203-tabs-vs-collapsegroup-/345/274/272/345/210/266.md +142 -142
- package/skills/uniapp-mall-assets/SKILL.md +176 -176
- package/skills/unity-integration/SKILL.md +171 -171
- package/skills/unity-integration/agents/openai.yaml +4 -4
- package/skills/unity-integration/references/ai-app-delivery.md +119 -119
- package/skills/unity-integration/references/sdk-api.md +82 -82
- package/skills/unity-integration/references/toolbox-migration.md +66 -66
- package/skills/unity-integration/references/webgl-hosting.md +57 -57
- package/skills/v8-api-config/SKILL.md +388 -388
- package/skills/v8-cache-pattern/SKILL.md +312 -312
- package/skills/v8-crud-api/SKILL.md +178 -178
- package/skills/v8-crud-api/references/progressive-01-/346/237/245/350/257/242/345/210/227/350/241/250-/345/210/206/351/241/265.md +226 -226
- package/skills/v8-crud-api/references/progressive-02-where-/346/235/241/344/273/266/350/257/255/346/263/225/351/200/237/346/237/245.md +49 -49
- package/skills/v8-debugging/SKILL.md +284 -284
- package/skills/v8-explorer-tree/SKILL.md +228 -228
- package/skills/v8-export-import/SKILL.md +219 -219
- package/skills/v8-export-import/references/progressive-01-excellayout-/351/253/230/347/272/247/350/207/252/347/224/261/345/270/203/345/261/200.md +211 -211
- package/skills/v8-export-import/references/progressive-02-powerpoint-/345/257/274/345/207/272.md +202 -202
- package/skills/v8-export-import/references/progressive-03-/345/256/211/345/205/250-/346/200/247/350/203/275/346/263/250/346/204/217.md +42 -42
- package/skills/v8-file-upload/SKILL.md +284 -284
- package/skills/v8-file-upload/references/progressive-01-/345/205/254/346/234/211/346/241/266-vs-/347/247/201/346/234/211/346/241/266.md +263 -263
- package/skills/v8-file-upload/references/progressive-02-office-/346/226/207/344/273/266/345/234/250/347/272/277/347/274/226/350/276/221/347/211/210/346/234/254/345/217/267/350/247/204/345/210/231.md +161 -161
- package/skills/v8-formengine-http/SKILL.md +238 -238
- package/skills/v8-frontend-events/SKILL.md +180 -180
- package/skills/v8-frontend-events/references/bluetooth-print-api.md +135 -135
- package/skills/v8-frontend-events/references/bluetooth-print.md +258 -258
- package/skills/v8-frontend-events/references/progressive-01-/345/210/227/350/241/250/344/272/213/344/273/266.md +219 -219
- package/skills/v8-http-integration/SKILL.md +182 -182
- package/skills/v8-http-integration/references/progressive-01-get-/350/257/267/346/261/202.md +220 -220
- package/skills/v8-http-integration/references/progressive-02-/351/224/231/350/257/257/345/244/204/347/220/206/346/250/241/345/274/217.md +44 -44
- package/skills/v8-image-processing/SKILL.md +190 -190
- package/skills/v8-image-processing/agents/openai.yaml +4 -4
- package/skills/v8-image-processing/references/api-reference.md +623 -623
- package/skills/v8-menu-buttons/SKILL.md +186 -186
- package/skills/v8-menu-buttons/references/progressive-01-2-/346/214/211/351/222/256/345/257/271/350/261/241-schema.md +222 -222
- package/skills/v8-menu-buttons/references/progressive-02-8-/346/250/241/345/274/217-f-/345/220/216/345/217/260/344/273/273/345/212/241/346/214/211/351/222/256-/351/225/277/344/273/273/345/212/241.md +228 -228
- package/skills/v8-menu-buttons/references/progressive-03-10-/345/217/215/346/250/241/345/274/217-/351/201/277/345/205/215.md +104 -104
- package/skills/v8-mongodb/SKILL.md +200 -200
- package/skills/v8-mq-mqtt/SKILL.md +176 -176
- package/skills/v8-mq-mqtt/references/mqtt-production.md +342 -342
- package/skills/v8-mq-mqtt/references/progressive-01-v8-mqtt-iot-/347/211/251/350/201/224/347/275/221.md +181 -181
- package/skills/v8-mq-mqtt/scripts/check-mqtt-skill-coverage.mjs +203 -203
- package/skills/v8-saas-multi-tenant/SKILL.md +305 -305
- package/skills/v8-security/SKILL.md +210 -210
- package/skills/v8-security/references/progressive-01-2-/346/235/203/351/231/220/346/240/241/351/252/214.md +200 -200
- package/skills/v8-security/references/progressive-02-7-/346/227/245/345/277/227/350/256/260/345/275/225.md +160 -160
- package/skills/v8-sql-query/SKILL.md +302 -302
- package/skills/v8-table-event/SKILL.md +176 -176
- package/skills/v8-table-event/references/progressive-01-informv8-js-/350/241/250/345/215/225/346/211/223/345/274/200/344/272/213/344/273/266.md +216 -216
- package/skills/v8-table-event/references/progressive-02-/345/211/215/347/253/257/344/272/213/344/273/266/345/220/215-v8-eventname-/345/217/257/350/203/275/347/232/204/345/200/274.md +46 -46
- package/skills/v8-tcp-integration/SKILL.md +147 -147
- package/skills/v8-tcp-integration/agents/openai.yaml +4 -4
- package/skills/v8-template-engine/SKILL.md +167 -167
- package/skills/v8-utilities/SKILL.md +104 -104
- package/skills/v8-utilities/references/client-api-index.md +143 -143
- package/skills/v8-utilities/references/platform-http-routes.md +83 -83
- package/skills/v8-utilities/references/server-api-index.md +188 -188
- package/skills/v8-workflow/SKILL.md +252 -252
- package/skills/v8-workflow/references/progressive-01-/350/212/202/347/202/271/345/274/200/345/247/213-v8-/344/272/213/344/273/266.md +180 -180
- package/skills/v8-workflow/references/workflow-configuration.md +49 -49
- package/skills/vision-engine/SKILL.md +160 -160
- package/skills/vision-engine/agents/openai.yaml +4 -4
- package/skills/vision-engine/references/architecture-and-acceptance.md +194 -194
- package/skills/workspace-conventions/SKILL.md +273 -273
- package/skills/workspace-conventions/references/progressive-01-/347/211/210/346/234/254/346/233/264/346/226/260/346/227/245/345/277/227/344/277/235/346/212/244/350/247/204/345/210/231-/345/274/272/345/210/266.md +209 -209
- package/skills/workspace-conventions/references/progressive-02-microi-net-api-/346/234/254/345/234/260/345/220/257/345/212/250/347/272/246/345/256/232.md +217 -217
- package/skills/workspace-conventions/references/progressive-03-cli-/344/270/216-ide-/346/217/222/344/273/266/351/224/231/347/211/210/345/205/261/345/255/230/347/272/246/345/256/232.md +27 -27
|
@@ -1,81 +1,81 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: email-engine
|
|
3
|
-
description: 开发、安装和使用吾码邮箱系统 mci-email。用于 QQ、163、126、企业或自定义 IMAP/SMTP 邮箱账号维护、自动与手动同步、邮件阅读、草稿、附件、回复转发、发送结果核对,以及邮箱 MCP 工具和 V8.Email 协议原子。
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# 吾码邮箱系统
|
|
7
|
-
|
|
8
|
-
> **Microi吾码基础规范(强制):** 任何 AI 模型与宿主每次新建或接续吾码任务,先完整读取 `../workspace-conventions/SKILL.md`,必须执行版本播报、`@microi.net/cli` 后台自动升级、Skills/MCP 同步和进度播报。安装与诊断读取 `../microi-codex-installer/SKILL.md`;更新失败延后重试,不阻断当前工作。
|
|
9
|
-
|
|
10
|
-
邮箱系统是使用吾码 UI 的独立 Vue 3 微服务,商城 AppKey 为 `mci-email`,
|
|
11
|
-
后台入口为「系统引擎 → 邮箱系统」,菜单路由 `/mci-email`。
|
|
12
|
-
|
|
13
|
-
先读取 `../workspace-conventions/SKILL.md`;开发或发布时还需读取
|
|
14
|
-
`../microi-microservice/SKILL.md`、`../app-store/SKILL.md`。
|
|
15
|
-
先调用 `microi_list_applications`,再读取目标应用完整上下文,禁止覆盖未读取的源码。
|
|
16
|
-
|
|
17
|
-
## 选择正确入口
|
|
18
|
-
|
|
19
|
-
| 需求 | 入口 |
|
|
20
|
-
| --- | --- |
|
|
21
|
-
| 邮箱工作台 | 源码微服务 `mci-email` |
|
|
22
|
-
| 账号配置 | 原表 `mic_email_server`,通过宿主 `openForm` 打开吾码表单 |
|
|
23
|
-
| 全部业务 HTTP | 接口引擎 `mci-email`,请求参数 `Action` |
|
|
24
|
-
| 手动同步 | `Action: Sync` 返回持久后台任务,使用 `SyncStatus` 回读终态 |
|
|
25
|
-
| 自动同步 | 定时任务调用 `mci-email-auto-sync`,内部调度 `mci-email-sync-step` |
|
|
26
|
-
| 协议、MIME、加密 | 最小后端原子 `V8.Email`,不新增业务 Controller |
|
|
27
|
-
| 租户扩展 | `mci-email-hook`,商城策略 `CreateIfMissing` |
|
|
28
|
-
| AI 操作 | `microi_email_query`、`microi_email_manage`、`microi_email_send` |
|
|
29
|
-
|
|
30
|
-
当前版本沿用原邮箱配置表的平台管理员权限(`Level >= 9999`),
|
|
31
|
-
并按当前用户检查账号和邮件所有权。不得因 AI 使用而绕过这些约束。
|
|
32
|
-
各运行节点需要包含 `V8.Email` 的平台版本;仅安装前端源码不能补齐 .NET 协议能力。
|
|
33
|
-
|
|
34
|
-
## 配置和同步
|
|
35
|
-
|
|
36
|
-
1. 确认用户拥有或获准使用邮箱;在服务商处开启 IMAP/SMTP,取得客户端授权码。
|
|
37
|
-
2. 打开账号表单,选择 QQ / 163 / 126 / 腾讯企业邮箱 / 自定义,填写地址与授权码。
|
|
38
|
-
3. QQ、163 常用 IMAP 993 / SMTP 465,选择 `SslOnConnect`;
|
|
39
|
-
使用 SMTP 587 时选择 `StartTls`。具体端口以服务商配置为准。
|
|
40
|
-
4. 授权码提交后由可信后端加密。编辑留空保留旧值;列表、导出、源码、日志和截图不含原文。
|
|
41
|
-
5. 先检测连接,再手动同步。首次先显示最新一批邮件,再增量补齐历史并核对状态。
|
|
42
|
-
6. 自动同步由平台定时任务运行,不依赖浏览器开着;每个账号设置同步间隔。
|
|
43
|
-
|
|
44
|
-
目录路径作为服务商的不透明值保存,不能自行翻译或改写。
|
|
45
|
-
去重键必须包含账号、目录、UIDVALIDITY 和 UID;UIDVALIDITY 改变时只重建该目录缓存。
|
|
46
|
-
同步锁使用接口引擎分布式锁,检查点进入数据库;进程重启后继续执行。
|
|
47
|
-
每批状态核对和近期摘要刷新都要先比较缓存,只更新实际变化的字段;未变化的 100 封邮件不能逐封重写。查询仅投影需要比较的标记/摘要字段,不加载正文或附件。跳过无变化写入仍须推进 UID 游标,保留远端删除、软删除恢复和已发送副本关联,并用同步回归测试验证。
|
|
48
|
-
邮件正文按需读取,默认阻止脚本、表单提交与外部图片;不能直接在宿主使用 `v-html`。
|
|
49
|
-
|
|
50
|
-
## MCP 使用
|
|
51
|
-
|
|
52
|
-
先通过 `microi_codex action=profiles` 选择用户指定租户,再按工具 Schema 调用。
|
|
53
|
-
|
|
54
|
-
```json
|
|
55
|
-
{"action":"Overview"}
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
以上参数用于 `microi_email_query`,不会回传授权码。
|
|
59
|
-
查询邮件用 `action: Messages`,可传 `accountId`、`folderKind`、`keyword`、
|
|
60
|
-
`pageIndex` 和 `pageSize`;只在任务需要时读取正文或附件。
|
|
61
|
-
|
|
62
|
-
维护工具先返回操作预览。用户已有明确授权后,`confirmExecution` 精确填写
|
|
63
|
-
`Action:目标Id`;新账号为 `SaveAccount:new`,新草稿为 `SaveDraft:账号Id`。
|
|
64
|
-
同步需要稳定的 `requestId`,恢复同一请求不得生成新值。
|
|
65
|
-
|
|
66
|
-
发信先通过 `microi_email_manage(action: SaveDraft)` 保存确定的收件人、正文与附件,
|
|
67
|
-
然后调用 `microi_email_send(draftId, confirmExecution: draftId)`。
|
|
68
|
-
只有用户已授权发送给这些收件人时才执行;不要把读取邮件的请求当作发送授权。
|
|
69
|
-
|
|
70
|
-
## 发送和结果边界
|
|
71
|
-
|
|
72
|
-
- 一次发送意图绑定稳定草稿 Id 和 Message-Id;同一草稿重复请求不能再次 SMTP 投递。
|
|
73
|
-
- `Sent` 表示 SMTP 服务器已接受;收件端可见需要实际收件验证。
|
|
74
|
-
- `Unknown` 表示连接中断等情况导致结果不确定,保留在发件箱,禁止自动重发。
|
|
75
|
-
先按 Message-Id 检查服务商已发送目录;确需新发时由用户确认新的发送意图。
|
|
76
|
-
- 远端已发送副本单独保存;副本或租户 Hook 失败不得回滚已发生的 SMTP 副作用。
|
|
77
|
-
- 原子只解密当前租户的凭据,不能向 V8 暴露解密方法;必须校验 TLS 证书。
|
|
78
|
-
|
|
79
|
-
协议方法和参数见 [V8.Email 原子参考](references/v8-email.md)。
|
|
80
|
-
最终分别验证源码/构建、API 权限、连接、实际收件、附件字节、重复发送、
|
|
81
|
-
自动同步、宿主表单、商城包与官网真实截图。
|
|
1
|
+
---
|
|
2
|
+
name: email-engine
|
|
3
|
+
description: 开发、安装和使用吾码邮箱系统 mci-email。用于 QQ、163、126、企业或自定义 IMAP/SMTP 邮箱账号维护、自动与手动同步、邮件阅读、草稿、附件、回复转发、发送结果核对,以及邮箱 MCP 工具和 V8.Email 协议原子。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 吾码邮箱系统
|
|
7
|
+
|
|
8
|
+
> **Microi吾码基础规范(强制):** 任何 AI 模型与宿主每次新建或接续吾码任务,先完整读取 `../workspace-conventions/SKILL.md`,必须执行版本播报、`@microi.net/cli` 后台自动升级、Skills/MCP 同步和进度播报。安装与诊断读取 `../microi-codex-installer/SKILL.md`;更新失败延后重试,不阻断当前工作。
|
|
9
|
+
|
|
10
|
+
邮箱系统是使用吾码 UI 的独立 Vue 3 微服务,商城 AppKey 为 `mci-email`,
|
|
11
|
+
后台入口为「系统引擎 → 邮箱系统」,菜单路由 `/mci-email`。
|
|
12
|
+
|
|
13
|
+
先读取 `../workspace-conventions/SKILL.md`;开发或发布时还需读取
|
|
14
|
+
`../microi-microservice/SKILL.md`、`../app-store/SKILL.md`。
|
|
15
|
+
先调用 `microi_list_applications`,再读取目标应用完整上下文,禁止覆盖未读取的源码。
|
|
16
|
+
|
|
17
|
+
## 选择正确入口
|
|
18
|
+
|
|
19
|
+
| 需求 | 入口 |
|
|
20
|
+
| --- | --- |
|
|
21
|
+
| 邮箱工作台 | 源码微服务 `mci-email` |
|
|
22
|
+
| 账号配置 | 原表 `mic_email_server`,通过宿主 `openForm` 打开吾码表单 |
|
|
23
|
+
| 全部业务 HTTP | 接口引擎 `mci-email`,请求参数 `Action` |
|
|
24
|
+
| 手动同步 | `Action: Sync` 返回持久后台任务,使用 `SyncStatus` 回读终态 |
|
|
25
|
+
| 自动同步 | 定时任务调用 `mci-email-auto-sync`,内部调度 `mci-email-sync-step` |
|
|
26
|
+
| 协议、MIME、加密 | 最小后端原子 `V8.Email`,不新增业务 Controller |
|
|
27
|
+
| 租户扩展 | `mci-email-hook`,商城策略 `CreateIfMissing` |
|
|
28
|
+
| AI 操作 | `microi_email_query`、`microi_email_manage`、`microi_email_send` |
|
|
29
|
+
|
|
30
|
+
当前版本沿用原邮箱配置表的平台管理员权限(`Level >= 9999`),
|
|
31
|
+
并按当前用户检查账号和邮件所有权。不得因 AI 使用而绕过这些约束。
|
|
32
|
+
各运行节点需要包含 `V8.Email` 的平台版本;仅安装前端源码不能补齐 .NET 协议能力。
|
|
33
|
+
|
|
34
|
+
## 配置和同步
|
|
35
|
+
|
|
36
|
+
1. 确认用户拥有或获准使用邮箱;在服务商处开启 IMAP/SMTP,取得客户端授权码。
|
|
37
|
+
2. 打开账号表单,选择 QQ / 163 / 126 / 腾讯企业邮箱 / 自定义,填写地址与授权码。
|
|
38
|
+
3. QQ、163 常用 IMAP 993 / SMTP 465,选择 `SslOnConnect`;
|
|
39
|
+
使用 SMTP 587 时选择 `StartTls`。具体端口以服务商配置为准。
|
|
40
|
+
4. 授权码提交后由可信后端加密。编辑留空保留旧值;列表、导出、源码、日志和截图不含原文。
|
|
41
|
+
5. 先检测连接,再手动同步。首次先显示最新一批邮件,再增量补齐历史并核对状态。
|
|
42
|
+
6. 自动同步由平台定时任务运行,不依赖浏览器开着;每个账号设置同步间隔。
|
|
43
|
+
|
|
44
|
+
目录路径作为服务商的不透明值保存,不能自行翻译或改写。
|
|
45
|
+
去重键必须包含账号、目录、UIDVALIDITY 和 UID;UIDVALIDITY 改变时只重建该目录缓存。
|
|
46
|
+
同步锁使用接口引擎分布式锁,检查点进入数据库;进程重启后继续执行。
|
|
47
|
+
每批状态核对和近期摘要刷新都要先比较缓存,只更新实际变化的字段;未变化的 100 封邮件不能逐封重写。查询仅投影需要比较的标记/摘要字段,不加载正文或附件。跳过无变化写入仍须推进 UID 游标,保留远端删除、软删除恢复和已发送副本关联,并用同步回归测试验证。
|
|
48
|
+
邮件正文按需读取,默认阻止脚本、表单提交与外部图片;不能直接在宿主使用 `v-html`。
|
|
49
|
+
|
|
50
|
+
## MCP 使用
|
|
51
|
+
|
|
52
|
+
先通过 `microi_codex action=profiles` 选择用户指定租户,再按工具 Schema 调用。
|
|
53
|
+
|
|
54
|
+
```json
|
|
55
|
+
{"action":"Overview"}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
以上参数用于 `microi_email_query`,不会回传授权码。
|
|
59
|
+
查询邮件用 `action: Messages`,可传 `accountId`、`folderKind`、`keyword`、
|
|
60
|
+
`pageIndex` 和 `pageSize`;只在任务需要时读取正文或附件。
|
|
61
|
+
|
|
62
|
+
维护工具先返回操作预览。用户已有明确授权后,`confirmExecution` 精确填写
|
|
63
|
+
`Action:目标Id`;新账号为 `SaveAccount:new`,新草稿为 `SaveDraft:账号Id`。
|
|
64
|
+
同步需要稳定的 `requestId`,恢复同一请求不得生成新值。
|
|
65
|
+
|
|
66
|
+
发信先通过 `microi_email_manage(action: SaveDraft)` 保存确定的收件人、正文与附件,
|
|
67
|
+
然后调用 `microi_email_send(draftId, confirmExecution: draftId)`。
|
|
68
|
+
只有用户已授权发送给这些收件人时才执行;不要把读取邮件的请求当作发送授权。
|
|
69
|
+
|
|
70
|
+
## 发送和结果边界
|
|
71
|
+
|
|
72
|
+
- 一次发送意图绑定稳定草稿 Id 和 Message-Id;同一草稿重复请求不能再次 SMTP 投递。
|
|
73
|
+
- `Sent` 表示 SMTP 服务器已接受;收件端可见需要实际收件验证。
|
|
74
|
+
- `Unknown` 表示连接中断等情况导致结果不确定,保留在发件箱,禁止自动重发。
|
|
75
|
+
先按 Message-Id 检查服务商已发送目录;确需新发时由用户确认新的发送意图。
|
|
76
|
+
- 远端已发送副本单独保存;副本或租户 Hook 失败不得回滚已发生的 SMTP 副作用。
|
|
77
|
+
- 原子只解密当前租户的凭据,不能向 V8 暴露解密方法;必须校验 TLS 证书。
|
|
78
|
+
|
|
79
|
+
协议方法和参数见 [V8.Email 原子参考](references/v8-email.md)。
|
|
80
|
+
最终分别验证源码/构建、API 权限、连接、实际收件、附件字节、重复发送、
|
|
81
|
+
自动同步、宿主表单、商城包与官网真实截图。
|
|
@@ -1,34 +1,34 @@
|
|
|
1
|
-
# V8.Email 协议原子
|
|
2
|
-
|
|
3
|
-
业务编排使用接口引擎,下面的方法只供可信后端调用。
|
|
4
|
-
连接对象字段为 `Host`、`Port`、`Security`、`UserName`、`Credential`、`Timeout`。
|
|
5
|
-
`Credential` 必须是 `V8.Email.ProtectCredential` 产生的当前租户密文。
|
|
6
|
-
`Security` 仅允许 `SslOnConnect`、`StartTls`。超时默认 40 秒,最高 60 秒。
|
|
7
|
-
|
|
8
|
-
| 方法 | 输入补充 | 返回 Data |
|
|
9
|
-
| --- | --- | --- |
|
|
10
|
-
| `V8.Email.ProtectCredential(value)` | 原文授权码 | 直接返回带版本前缀的租户密文字符串 |
|
|
11
|
-
| `V8.Email.TestConnection(p)` | `Protocol: IMAP / SMTP` | `Connected, Protocol, Secure` |
|
|
12
|
-
| `V8.Email.ListFolders(p)` | 无 | 最多 200 个 `Path, Name, Kind, Total, Unread` |
|
|
13
|
-
| `V8.Email.Fetch(p)` | `Folder, AfterUid, UidValidity, Limit, Recent` | `NextUid, HasMore, Reset, UidValidity, Messages` |
|
|
14
|
-
| `V8.Email.Inspect(p)` | `Folder, UidValidity, Uids`(最多 100) | `UidValidity, Messages`,含存在的 UID 和已读/星标/删除标志 |
|
|
15
|
-
| `V8.Email.GetMessage(p)` | `Folder, UidValidity, Uid` | 信封、`TextBody, HtmlBody, Attachments` |
|
|
16
|
-
| `V8.Email.GetAttachment(p)` | 上述字段及 `AttachmentIndex`(从 0 开始) | `FileName, ContentType, FileByteBase64` |
|
|
17
|
-
| `V8.Email.SetFlags(p)` | `Folder, UidValidity, Uid, IsRead, IsStarred` | 结果状态 |
|
|
18
|
-
| `V8.Email.Move(p)` | `Folder, UidValidity, Uid, DestinationFolder` | 移动结果;不得对整个目录执行无差别清空 |
|
|
19
|
-
| `V8.Email.Send(p)` | SMTP 连接及下述 MIME 字段 | `DeliveryState, MessageId`,外层 `Code` 表示协议结果 |
|
|
20
|
-
| `V8.Email.StoreSent(p)` | IMAP 连接及相同 MIME 字段 | 按 Message-Id 查重并保存已发送副本 |
|
|
21
|
-
|
|
22
|
-
`Fetch.Recent=true` 读取末尾最多 `Limit` 封邮件,但保留历史 `AfterUid` 游标。
|
|
23
|
-
常规 Fetch 按 UID 窗口分页,`Limit` 最高 100;即使窗口为空也推进游标。
|
|
24
|
-
返回的 `Reset` 必须与 `UidValidity` 一起持久化,不能把旧代邮件指向新代同号 UID。
|
|
25
|
-
|
|
26
|
-
MIME 字段:`To, Cc, Bcc, Subject, TextBody, HtmlBody, InReplyTo, MessageId, Attachments`。
|
|
27
|
-
附件对象:`FileName, ContentType, FileByteBase64`,最多 10 个,总大小不超过 10MB;
|
|
28
|
-
读取单封原始邮件上限 25MB,正文上限 2MB。超限应明确报错,不能静默丢内容。
|
|
29
|
-
|
|
30
|
-
`Send` 的结果:`Accepted`、`Rejected` 或 `Unknown`。
|
|
31
|
-
在业务层保存草稿及去重标记后才能调用;不要对 `Unknown` 自动重试 SMTP。
|
|
32
|
-
`StoreSent` 与真正发信分开,不可将保存副本当作已经投递。
|
|
33
|
-
|
|
34
|
-
相关源码:`Microi.Server/Microi.V8Engine/Extend/Email/V8Email.cs`。
|
|
1
|
+
# V8.Email 协议原子
|
|
2
|
+
|
|
3
|
+
业务编排使用接口引擎,下面的方法只供可信后端调用。
|
|
4
|
+
连接对象字段为 `Host`、`Port`、`Security`、`UserName`、`Credential`、`Timeout`。
|
|
5
|
+
`Credential` 必须是 `V8.Email.ProtectCredential` 产生的当前租户密文。
|
|
6
|
+
`Security` 仅允许 `SslOnConnect`、`StartTls`。超时默认 40 秒,最高 60 秒。
|
|
7
|
+
|
|
8
|
+
| 方法 | 输入补充 | 返回 Data |
|
|
9
|
+
| --- | --- | --- |
|
|
10
|
+
| `V8.Email.ProtectCredential(value)` | 原文授权码 | 直接返回带版本前缀的租户密文字符串 |
|
|
11
|
+
| `V8.Email.TestConnection(p)` | `Protocol: IMAP / SMTP` | `Connected, Protocol, Secure` |
|
|
12
|
+
| `V8.Email.ListFolders(p)` | 无 | 最多 200 个 `Path, Name, Kind, Total, Unread` |
|
|
13
|
+
| `V8.Email.Fetch(p)` | `Folder, AfterUid, UidValidity, Limit, Recent` | `NextUid, HasMore, Reset, UidValidity, Messages` |
|
|
14
|
+
| `V8.Email.Inspect(p)` | `Folder, UidValidity, Uids`(最多 100) | `UidValidity, Messages`,含存在的 UID 和已读/星标/删除标志 |
|
|
15
|
+
| `V8.Email.GetMessage(p)` | `Folder, UidValidity, Uid` | 信封、`TextBody, HtmlBody, Attachments` |
|
|
16
|
+
| `V8.Email.GetAttachment(p)` | 上述字段及 `AttachmentIndex`(从 0 开始) | `FileName, ContentType, FileByteBase64` |
|
|
17
|
+
| `V8.Email.SetFlags(p)` | `Folder, UidValidity, Uid, IsRead, IsStarred` | 结果状态 |
|
|
18
|
+
| `V8.Email.Move(p)` | `Folder, UidValidity, Uid, DestinationFolder` | 移动结果;不得对整个目录执行无差别清空 |
|
|
19
|
+
| `V8.Email.Send(p)` | SMTP 连接及下述 MIME 字段 | `DeliveryState, MessageId`,外层 `Code` 表示协议结果 |
|
|
20
|
+
| `V8.Email.StoreSent(p)` | IMAP 连接及相同 MIME 字段 | 按 Message-Id 查重并保存已发送副本 |
|
|
21
|
+
|
|
22
|
+
`Fetch.Recent=true` 读取末尾最多 `Limit` 封邮件,但保留历史 `AfterUid` 游标。
|
|
23
|
+
常规 Fetch 按 UID 窗口分页,`Limit` 最高 100;即使窗口为空也推进游标。
|
|
24
|
+
返回的 `Reset` 必须与 `UidValidity` 一起持久化,不能把旧代邮件指向新代同号 UID。
|
|
25
|
+
|
|
26
|
+
MIME 字段:`To, Cc, Bcc, Subject, TextBody, HtmlBody, InReplyTo, MessageId, Attachments`。
|
|
27
|
+
附件对象:`FileName, ContentType, FileByteBase64`,最多 10 个,总大小不超过 10MB;
|
|
28
|
+
读取单封原始邮件上限 25MB,正文上限 2MB。超限应明确报错,不能静默丢内容。
|
|
29
|
+
|
|
30
|
+
`Send` 的结果:`Accepted`、`Rejected` 或 `Unknown`。
|
|
31
|
+
在业务层保存草稿及去重标记后才能调用;不要对 `Unknown` 自动重试 SMTP。
|
|
32
|
+
`StoreSent` 与真正发信分开,不可将保存副本当作已经投递。
|
|
33
|
+
|
|
34
|
+
相关源码:`Microi.Server/Microi.V8Engine/Extend/Email/V8Email.cs`。
|
|
@@ -1,176 +1,176 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: job-engine
|
|
3
|
-
description: Microi 定时任务与可靠后台任务规范。用于配置 Microi.Job、Quartz 和接口引擎任务,设计多节点租约、幂等、重试、停机排空、恢复、进度与验收。
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
> **Microi吾码基础规范(强制):** 任何 AI 模型与宿主每次新建或接续吾码任务,先完整读取 `../workspace-conventions/SKILL.md`,必须执行版本播报、`@microi.net/cli` 后台自动升级、Skills/MCP 同步和进度播报。安装与诊断读取 `../microi-codex-installer/SKILL.md`;更新失败延后重试,不阻断当前工作。
|
|
7
|
-
|
|
8
|
-
# Microi Job 定时与后台任务
|
|
9
|
-
|
|
10
|
-
## 何时使用
|
|
11
|
-
|
|
12
|
-
- 周期扫描、补偿、归档:`Microi.Job`
|
|
13
|
-
- 用户触发的长耗时安装/导入/同步:菜单后台任务
|
|
14
|
-
- 可靠跨服务异步:MQ + outbox/inbox
|
|
15
|
-
- 请求内等待外部结果:`await`,不要创建后台线程
|
|
16
|
-
|
|
17
|
-
禁止用后端 `setTimeout`、`Task.Run`、`static bool` 或本机定时器承载可靠业务。
|
|
18
|
-
|
|
19
|
-
## 持续模拟不使用秒级任务冒充
|
|
20
|
-
|
|
21
|
-
需要50ms规则步长的持续模拟应使用已安装的通用受信后台宿主,规则留应用包、业务事务留接口引擎。`NextDelaySeconds:1` 或每秒Quartz任务只能扫描租约、恢复检查点与补偿;HasMore分片不等于20Hz实时tick。后台恢复必须拥有服务端可信作用域并重读主库,不可伪造成员DiyToken或复用已过期pump scope。无法证明实际后台连续推进时,只能报告请求触发/秒级补偿,不得声称已经提供持续权威模拟。
|
|
22
|
-
|
|
23
|
-
## 平台对象
|
|
24
|
-
|
|
25
|
-
Quartz 管理能力包含查询、添加、更新、暂停、恢复、删除任务。V8 中的 `V8.Method.ManageScheduleJob` 用于能力发现、任务查询和受控管理,必须绑定当前租户的管理员身份。任务配置、接口引擎代码和执行日志属于控制面,只允许 `Level >= 9999` 维护;业务用户只能触发明确授权的后台动作。
|
|
26
|
-
|
|
27
|
-
任务通常调用稳定的 `ApiEngineKey`。接口引擎返回 `Code=1` 只表示本次执行成功,不代表调度系统可忽略重试与幂等。
|
|
28
|
-
|
|
29
|
-
## 多节点设计
|
|
30
|
-
|
|
31
|
-
### 执行日志与只读诊断
|
|
32
|
-
|
|
33
|
-
- 新执行/失败/跳过记录使用 `ScheduleExecutionLog`,直接等待 MongoDB 确认写入 `sys_log_<tenant>/log_yyyyMM`;固定 `TargetType=ScheduledJob`、`TargetId=JobName`,`EventId` 幂等。MongoDB 确认失败才写当前租户的 `diy_schedule_job_log`,两者均失败不得改变业务结果。`AddSysLog` 仅代表异步入队,不能用作本能力的持久化确认。
|
|
34
|
-
- 表单使用字段级 Tabs,分别放置“运行日志”和“历史日志”只读表格;仅显示的页签发起查询。历史 `diy_schedule_job_log` 保留,不自动删除、搬迁或清空。
|
|
35
|
-
- `platform-schedule-job` 的 `logs/historylogs` 要求任务名、月份,每页最多 100 条,按时间+Id 游标多取一条判断 `HasMore`,不计算多年数据总数。Mongo 索引为 `(TargetType,TargetId,CreateTime,EventId)`;历史表索引 `(JobName,CreateTime,Id)` 通过声明式应用包交付并现场回读。
|
|
36
|
-
- 用 `microi_query_job_runtime` 或 `microi_run_engine` 的 `Action=diagnostics` 核验启动、待机、实际执行数、领取进展、设置读取失败、触发器与心跳。一个租户的设置读取超时只能关闭该租户,不能拖住其它租户;每租户最多一个在途读,不能按轮询叠加请求。
|
|
37
|
-
- `logs` 优先读 MongoDB,MongoDB 查询失败时自动读关系库;成功的空集合不回退。`historylogs` 固定读关系库。两个库都不可用必须显示查询失败,不能伪装为空日志。镜像更新不等于 Mongo 升级;后台系统日志队列的 spool 仍应在持久卷并验收恢复重放。
|
|
38
|
-
|
|
39
|
-
### 运行时间刷新与配置版本分离
|
|
40
|
-
|
|
41
|
-
- Quartz 周期同步 `LastTime/NextTime` 是运行状态投影,不能调用通用 `UptFormData` 生成配置版本或数据日志;用户保存名称、Cron、代码等配置仍走原表单事件和版本链路。
|
|
42
|
-
- 只读取 Id、任务名和两个时间列;时间未变化时不写入。变化时由可信调度内核向同一租户主库执行固定两列参数化 CAS,匹配原时间、任务名、正常状态与未删除条件;并发/陈旧结果命中 0 行时不重放。
|
|
43
|
-
- 编辑 Cron 重建触发器后,Quartz 的 PreviousFireTime 可能为空;同步时不得因此清空数据库已有的 `LastTime`,新的 `NextTime` 仍应更新。验收需覆盖“已执行任务改到当天已过时间,下一次排到次日”的场景,并分别核对新旧执行日志。
|
|
44
|
-
- 历史版本保留不自动删除。持续高 CPU 时核对 `mic_data_version` 实际物理索引,不以应用包已声明索引推断旧库已安装;用 MCP 回读 `(TableId,TableRowId,CreateTime)`,并比较 MySQL digest 两次采样的执行数、扫描行数与耗时差值。
|
|
45
|
-
- 此修复要求更新调度后端;既有 `platform-schedule-job`、任务元数据及 MCP 查询/保存协议保持兼容。验收覆盖两租户同名任务、两连接竞争、未变化、暂停/软删除/重命名后陈旧写入、主库选择和配置字段不变。
|
|
46
|
-
|
|
47
|
-
### 新旧平台共库过渡:停用新版调度
|
|
48
|
-
|
|
49
|
-
- 系统设置“开发配置”的 `DisableTaskScheduling`(停用任务调度)默认 `0`,缺字段、空值也按正常调度处理;只有已实现此能力的新版后端识别它。字段由“系统设置”应用和 SaaS 空库基础包交付,不写租户配置值,不逐条 Pause/修改任务状态。
|
|
50
|
-
- 开启时在 Quartz 领取触发器、处理 Misfire 之前按租户过滤;领取后、真正触发前重新读取系统设置缓存。禁止仅在 `IJob.Execute`、Listener veto 或业务 V8 入口 return:共享 Quartz 可能已经推进 NextFireTime,造成旧版漏执行。
|
|
51
|
-
- 集群故障恢复也不得清理停用租户的在途记录或创建其补偿触发器。Quartz 以故障节点为单位清理记录,所以同一故障节点混有被停用租户时,新版推迟该故障节点整组恢复,交给旧节点或关闭开关后处理;其它健康节点仍正常领取。
|
|
52
|
-
- 正常保存系统设置在事务提交后失效缓存,下一次调度检查生效,不用重启;不是强制中断,已经开始的任务允许完成。缓存/配置读取失败拒绝该租户的新领取,不影响其它健康租户;Redis/失效通知异常时不能承诺硬实时。
|
|
53
|
-
- 停用期间只读观察周期计划,不推进共享触发器;每个“租户 + Job + Trigger + 计划时间”持久化确定性事件,包含 `Status=Skipped`、`Executed=false`、`Reason=SystemTaskSchedulingDisabled` 和中文说明。Redis 原子预留与日志确定性主键共同防止多新版节点重复记录;日志说明仅代表新版未执行,旧版仍可能正常执行。不补跑业务、不补写进程停机历史;新增/修改计划的日志目录最多约 10 秒更新。
|
|
54
|
-
- 普通接口调用、MQ 消费、升级/应用安装等持久后台任务不属于此开关的范围。手动触发 Quartz 任务仍经过门禁。
|
|
55
|
-
- 交付顺序:先安装字段并打开开关,再让新版节点参与调度;确认旧版所有调度进程已停止且在途任务完成后,关闭开关交接。不同业务库分别设置,不能用一个租户的值控制全部租户。
|
|
56
|
-
- 验收至少覆盖:默认兼容、开关实时读取、租户隔离、共享库旧节点继续领取、领取后开关变化不推进触发器、Misfire 不误推进、多节点日志去重;不得在真实生产任务上制造副作用做测试。
|
|
57
|
-
|
|
58
|
-
每个任务必须同时具备:
|
|
59
|
-
|
|
60
|
-
1. 分布式租约:Key 至少含 `OsClient + JobKey + 计划时间/业务分片`,有唯一持有者、TTL、续租和仅持有者释放。
|
|
61
|
-
2. 业务幂等:稳定 `IdempotencyKey/EventId`、数据库唯一约束或条件状态迁移。
|
|
62
|
-
3. 可恢复状态:待处理、处理中、成功、失败、下次重试时间写共享数据库/Redis/MQ。
|
|
63
|
-
4. fencing:锁可能过期的资金、库存等任务使用版本号/条件更新拒绝旧持有者写入。
|
|
64
|
-
|
|
65
|
-
锁只能减少并发,不能替代幂等。
|
|
66
|
-
|
|
67
|
-
## 任务骨架
|
|
68
|
-
|
|
69
|
-
```js
|
|
70
|
-
// 接口引擎由 Job 调用;JobRunId/FireTime 由调度层传入
|
|
71
|
-
var idempotencyKey = String(V8.Param.JobRunId || '');
|
|
72
|
-
if (!idempotencyKey) return { Code: 0, Msg: '缺少 JobRunId' };
|
|
73
|
-
|
|
74
|
-
// 推荐调用专用后端能力,以唯一约束抢占执行记录
|
|
75
|
-
var claim = V8.FormEngine.AddFormData('job_execution', {
|
|
76
|
-
JobKey: 'daily_order_summary',
|
|
77
|
-
IdempotencyKey: idempotencyKey,
|
|
78
|
-
Status: 'Running'
|
|
79
|
-
});
|
|
80
|
-
if (claim.Code !== 1) return { Code: 1, Msg: '已执行或正在执行' };
|
|
81
|
-
|
|
82
|
-
// 分页处理;每个业务副作用仍需自己的幂等键
|
|
83
|
-
return { Code: 1, Data: { IdempotencyKey: idempotencyKey } };
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
实际项目优先由数据库唯一索引和接口引擎事务完成抢占,不能仅用“先查再新增”。该唯一索引必须声明在 Manifest `tables[].indexes`,并用 `microi_create_table_index` 创建、`microi_get_table_indexes` 回读;禁止在 Job/V8 内手写 `CREATE INDEX`。任务扫描还应按实际 SQL 建立 `(OsClient, Status, NextRetryTime)` 或 `(OsClient, JobKey, ScheduleTime)` 等组合索引。
|
|
87
|
-
|
|
88
|
-
## 失败、重试与停机
|
|
89
|
-
|
|
90
|
-
- 先证明任务真的在执行:读 `Scheduler.IsStarted`、`Scheduler.NumberOfJobsExecuted` 和 `Acquisition.LastAcquisitionError`,参考 `microi.doc/docs/doc/system-engine/job.md` 的“任务不执行”。`diy_schedule_job.Status=正常`、`diy_schedule_job.NextTime` 和“插件启动成功”都不能证明触发成功;列表/详情页的 `LastTime/NextTime` 来自运行时,直接查表看到的是库内快照。
|
|
91
|
-
- 领取错误含 `Key 'IDX_microi_job_T_NFT_ST' doesn't exist` 时,是 Quartz 3.19 MySQL 方言依赖 `USE INDEX (IDX_{tablePrefix}T_NFT_ST)` 与 `IDX_{tablePrefix}T_NFT_ST_MISFIRE`,而触发器表缺少这两个索引(常见于历史租户库仍是旧 `QRTZ_` 前缀索引名)。平台调度器初始化会按前缀幂等补齐;人工抢修可直接执行文档中的两条 `CREATE INDEX`,索引名大小写不敏感,补完后无需重建任务或 Cron。
|
|
92
|
-
- 失败记录错误分类、重试次数和 `NextRetryTime`,采用有上限退避;永久错误进入人工处理。
|
|
93
|
-
- 外部调用设置超时;无法确认对方是否成功时用业务幂等号查询,不盲目重发。
|
|
94
|
-
- 服务停机先停止接单,再在有限宽限期排空或持久化;重启扫描未完成任务。
|
|
95
|
-
- 若要求 `kill -9` 前也零丢失,业务成功响应前必须获得共享 outbox/MQ/WAL 持久化确认。
|
|
96
|
-
|
|
97
|
-
## 后台按钮
|
|
98
|
-
|
|
99
|
-
满足任一条件即按后台任务设计:预计超过 2 分钟、500 条以上、1000 个以上扇出子操作、100 次以上外部调用、总量未知且可能持续运行,或安装/初始化/批量导入/批量生成/全量同步/迁移/备份。预计超过 10 分钟时,仅设置 `RunBackground=true` 仍不够,必须按 checkpoint 分片,每片独立事务。
|
|
100
|
-
|
|
101
|
-
菜单按钮设置 `RunBackground/BackgroundTask/IsBackgroundTask=true` 和 `ApiEngineKey`,并配置 `BackgroundTaskOptions`:
|
|
102
|
-
|
|
103
|
-
- `IdempotencyKey` 或 `IdempotencyKeyFields`:跨节点、重试和重复点击保持稳定。
|
|
104
|
-
- `ConcurrencyKey`:DDL、安装等不能并行的工作使用同一租约组。
|
|
105
|
-
- `BusinessTable + BusinessId`:关联业务记录。
|
|
106
|
-
- `BusinessStatusField + BusinessTaskIdField`:业务记录至少标记“后台处理中”和任务 Id;推荐再配置 `BusinessProgressField + BusinessEtaField`。
|
|
107
|
-
|
|
108
|
-
按钮提交成功后,平台前端会通过当前用户的 `V8.FormEngine` 权限把业务记录标记为“后台处理中”并写入任务 Id;后台服务不能直接相信客户端字段名而绕过表单权限。接口引擎仍必须在最后一片或异常补偿中把该业务记录改成“已完成 / 失败 / 已取消”,并保留任务 Id 供详情追溯:
|
|
109
|
-
|
|
110
|
-
```js
|
|
111
|
-
var task = V8.Param._BackgroundTask || {};
|
|
112
|
-
if (task.BusinessTable && task.BusinessId) {
|
|
113
|
-
var patch = { Id: task.BusinessId };
|
|
114
|
-
patch[task.BusinessStatusField] = '后台处理中';
|
|
115
|
-
patch[task.BusinessTaskIdField] = task.Id;
|
|
116
|
-
V8.FormEngine.UptFormData(task.BusinessTable, patch);
|
|
117
|
-
}
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
不得让通用后台服务按客户端传入的任意表名/字段名直接写库;需要脱离前端自动标记的专用任务,应在受控接口引擎中使用固定表名和固定字段名。
|
|
121
|
-
|
|
122
|
-
接口通过 `V8.Method.UpdateBackgroundTask({Current,Total,Msg,Log})` 上报已提交的真实工作量,`Log`/`AppendLog` 用于追加任务详情(不得包含密码、Token 或密钥)。平台按实际吞吐计算 `EstimatedEndTime`;总量未知时不传 `Total`,通知中心显示“不定进度/估算中”,禁止用固定 10%、阶段占位或计时器伪造进度。失败和取消停在最后真实进度,不得显示 100%。
|
|
123
|
-
|
|
124
|
-
分片接口在仍有后续工作时返回:
|
|
125
|
-
|
|
126
|
-
```js
|
|
127
|
-
return {
|
|
128
|
-
Code: 1,
|
|
129
|
-
Data: {
|
|
130
|
-
BackgroundTask: {
|
|
131
|
-
HasMore: true,
|
|
132
|
-
Checkpoint: { LastId: lastId },
|
|
133
|
-
Current: committedCount,
|
|
134
|
-
Total: totalCount,
|
|
135
|
-
NextDelaySeconds: 1,
|
|
136
|
-
Msg: '本批已提交,等待下一批'
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
};
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
最后一片返回普通 `Code:1`。每个业务副作用还要用 `_BackgroundTaskIdempotencyKey + 业务行Id` 建唯一约束;`_BackgroundTaskFencingToken` 用于拒绝租约过期旧执行者的写入。
|
|
143
|
-
|
|
144
|
-
## 长任务的 Jint 预算
|
|
145
|
-
|
|
146
|
-
后台 Worker 最终仍调用接口引擎,因此每个执行片段都受 `Timeout`、`MaxStatements`、单层累计分配预算、根调用树累计分配预算、JavaScript 递归和接口嵌套深度限制。`LimitMemory=2048` 表示当前片段累计分配了多少托管字节,不表示实时占用或预留 2GB 物理内存。
|
|
147
|
-
|
|
148
|
-
- 总任务运行 10 分钟、30 分钟或数小时是允许的;单个连续 Jint 调用不应承担全部时长。
|
|
149
|
-
- 每片在预算内提交事务并返回 `HasMore + Checkpoint`;Worker 重新入队后会创建新的 Jint Engine,新片重新获得超时、语句和累计分配预算。
|
|
150
|
-
- `V8.ApiEngine.Run` 的多层编排可以保留。新版父子单层分配隔离后,子接口不会被所有祖先重复计费,但根调用树仍有整体预算;循环调用由独立的嵌套深度上限终止。
|
|
151
|
-
- 捕获失败时读取 `DataAppend.V8Limit.Code`。内存/调用树/语句/超时分别缩小批次,递归错误修复函数递归,嵌套深度错误检查循环编排;不要统一归因于服务器资源不足。
|
|
152
|
-
- 可记录 `V8.Limits` 到脱敏诊断日志,但不要在每条业务数据上重复输出。
|
|
153
|
-
- 接口引擎和表后端事件分别使用正向 `sys_apiengine.V8Limit`、`diy_table.V8Limit`;二者默认 `0`,不设置 Jint 单片预算,只有明确需要限制单片时才设为 `1` 并配置超时、语句、分配和递归值。后台任务仍优先 `HasMore + Checkpoint`,因为不限 Jint 预算不等于数据库长事务、进程常驻内存、取消、并发或节点故障风险消失。
|
|
154
|
-
|
|
155
|
-
## MCP 工作流
|
|
156
|
-
|
|
157
|
-
1. 读取表、接口引擎和现有任务。
|
|
158
|
-
2. 先设计幂等键、状态机、租约和补偿。
|
|
159
|
-
3. `microi_save_job` 保存任务,写入需明确确认。
|
|
160
|
-
4. 回读任务 cron、启用状态、Key、接口引擎。
|
|
161
|
-
5. 两节点同时触发、重复投递、持有者中止、Redis 故障和滚动升级验收。
|
|
162
|
-
|
|
163
|
-
## 验收清单
|
|
164
|
-
|
|
165
|
-
- [ ] 任务配置仅管理员可改
|
|
166
|
-
- [ ] 两节点同一时刻触发,业务副作用仅一次
|
|
167
|
-
- [ ] 重复消息/请求不会重复扣减或生成流水
|
|
168
|
-
- [ ] 锁持有者退出后可恢复,无永久死锁
|
|
169
|
-
- [ ] 失败可重试、可追踪、可人工补偿
|
|
170
|
-
- [ ] 新旧版本滚动共存,状态和消息合约兼容
|
|
171
|
-
- [ ] 未知总量不显示假百分比;已知总量由 Current/Total 唯一推导
|
|
172
|
-
- [ ] ETA 来自真实吞吐,样本不足时明确显示“估算中”
|
|
173
|
-
- [ ] 业务记录可通过 BackgroundTaskId 跳转通知中心排查
|
|
174
|
-
- [ ] 超过 10 分钟的任务有 checkpoint,重启后从最后已提交批次恢复
|
|
175
|
-
- [ ] 单片低于超时/语句/累计分配预算,任务总时长不依赖放大单次接口上限
|
|
176
|
-
- [ ] 嵌套接口没有循环调用,且错误日志包含结构化 `V8Limit` 分类和调用路径
|
|
1
|
+
---
|
|
2
|
+
name: job-engine
|
|
3
|
+
description: Microi 定时任务与可靠后台任务规范。用于配置 Microi.Job、Quartz 和接口引擎任务,设计多节点租约、幂等、重试、停机排空、恢复、进度与验收。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
> **Microi吾码基础规范(强制):** 任何 AI 模型与宿主每次新建或接续吾码任务,先完整读取 `../workspace-conventions/SKILL.md`,必须执行版本播报、`@microi.net/cli` 后台自动升级、Skills/MCP 同步和进度播报。安装与诊断读取 `../microi-codex-installer/SKILL.md`;更新失败延后重试,不阻断当前工作。
|
|
7
|
+
|
|
8
|
+
# Microi Job 定时与后台任务
|
|
9
|
+
|
|
10
|
+
## 何时使用
|
|
11
|
+
|
|
12
|
+
- 周期扫描、补偿、归档:`Microi.Job`
|
|
13
|
+
- 用户触发的长耗时安装/导入/同步:菜单后台任务
|
|
14
|
+
- 可靠跨服务异步:MQ + outbox/inbox
|
|
15
|
+
- 请求内等待外部结果:`await`,不要创建后台线程
|
|
16
|
+
|
|
17
|
+
禁止用后端 `setTimeout`、`Task.Run`、`static bool` 或本机定时器承载可靠业务。
|
|
18
|
+
|
|
19
|
+
## 持续模拟不使用秒级任务冒充
|
|
20
|
+
|
|
21
|
+
需要50ms规则步长的持续模拟应使用已安装的通用受信后台宿主,规则留应用包、业务事务留接口引擎。`NextDelaySeconds:1` 或每秒Quartz任务只能扫描租约、恢复检查点与补偿;HasMore分片不等于20Hz实时tick。后台恢复必须拥有服务端可信作用域并重读主库,不可伪造成员DiyToken或复用已过期pump scope。无法证明实际后台连续推进时,只能报告请求触发/秒级补偿,不得声称已经提供持续权威模拟。
|
|
22
|
+
|
|
23
|
+
## 平台对象
|
|
24
|
+
|
|
25
|
+
Quartz 管理能力包含查询、添加、更新、暂停、恢复、删除任务。V8 中的 `V8.Method.ManageScheduleJob` 用于能力发现、任务查询和受控管理,必须绑定当前租户的管理员身份。任务配置、接口引擎代码和执行日志属于控制面,只允许 `Level >= 9999` 维护;业务用户只能触发明确授权的后台动作。
|
|
26
|
+
|
|
27
|
+
任务通常调用稳定的 `ApiEngineKey`。接口引擎返回 `Code=1` 只表示本次执行成功,不代表调度系统可忽略重试与幂等。
|
|
28
|
+
|
|
29
|
+
## 多节点设计
|
|
30
|
+
|
|
31
|
+
### 执行日志与只读诊断
|
|
32
|
+
|
|
33
|
+
- 新执行/失败/跳过记录使用 `ScheduleExecutionLog`,直接等待 MongoDB 确认写入 `sys_log_<tenant>/log_yyyyMM`;固定 `TargetType=ScheduledJob`、`TargetId=JobName`,`EventId` 幂等。MongoDB 确认失败才写当前租户的 `diy_schedule_job_log`,两者均失败不得改变业务结果。`AddSysLog` 仅代表异步入队,不能用作本能力的持久化确认。
|
|
34
|
+
- 表单使用字段级 Tabs,分别放置“运行日志”和“历史日志”只读表格;仅显示的页签发起查询。历史 `diy_schedule_job_log` 保留,不自动删除、搬迁或清空。
|
|
35
|
+
- `platform-schedule-job` 的 `logs/historylogs` 要求任务名、月份,每页最多 100 条,按时间+Id 游标多取一条判断 `HasMore`,不计算多年数据总数。Mongo 索引为 `(TargetType,TargetId,CreateTime,EventId)`;历史表索引 `(JobName,CreateTime,Id)` 通过声明式应用包交付并现场回读。
|
|
36
|
+
- 用 `microi_query_job_runtime` 或 `microi_run_engine` 的 `Action=diagnostics` 核验启动、待机、实际执行数、领取进展、设置读取失败、触发器与心跳。一个租户的设置读取超时只能关闭该租户,不能拖住其它租户;每租户最多一个在途读,不能按轮询叠加请求。
|
|
37
|
+
- `logs` 优先读 MongoDB,MongoDB 查询失败时自动读关系库;成功的空集合不回退。`historylogs` 固定读关系库。两个库都不可用必须显示查询失败,不能伪装为空日志。镜像更新不等于 Mongo 升级;后台系统日志队列的 spool 仍应在持久卷并验收恢复重放。
|
|
38
|
+
|
|
39
|
+
### 运行时间刷新与配置版本分离
|
|
40
|
+
|
|
41
|
+
- Quartz 周期同步 `LastTime/NextTime` 是运行状态投影,不能调用通用 `UptFormData` 生成配置版本或数据日志;用户保存名称、Cron、代码等配置仍走原表单事件和版本链路。
|
|
42
|
+
- 只读取 Id、任务名和两个时间列;时间未变化时不写入。变化时由可信调度内核向同一租户主库执行固定两列参数化 CAS,匹配原时间、任务名、正常状态与未删除条件;并发/陈旧结果命中 0 行时不重放。
|
|
43
|
+
- 编辑 Cron 重建触发器后,Quartz 的 PreviousFireTime 可能为空;同步时不得因此清空数据库已有的 `LastTime`,新的 `NextTime` 仍应更新。验收需覆盖“已执行任务改到当天已过时间,下一次排到次日”的场景,并分别核对新旧执行日志。
|
|
44
|
+
- 历史版本保留不自动删除。持续高 CPU 时核对 `mic_data_version` 实际物理索引,不以应用包已声明索引推断旧库已安装;用 MCP 回读 `(TableId,TableRowId,CreateTime)`,并比较 MySQL digest 两次采样的执行数、扫描行数与耗时差值。
|
|
45
|
+
- 此修复要求更新调度后端;既有 `platform-schedule-job`、任务元数据及 MCP 查询/保存协议保持兼容。验收覆盖两租户同名任务、两连接竞争、未变化、暂停/软删除/重命名后陈旧写入、主库选择和配置字段不变。
|
|
46
|
+
|
|
47
|
+
### 新旧平台共库过渡:停用新版调度
|
|
48
|
+
|
|
49
|
+
- 系统设置“开发配置”的 `DisableTaskScheduling`(停用任务调度)默认 `0`,缺字段、空值也按正常调度处理;只有已实现此能力的新版后端识别它。字段由“系统设置”应用和 SaaS 空库基础包交付,不写租户配置值,不逐条 Pause/修改任务状态。
|
|
50
|
+
- 开启时在 Quartz 领取触发器、处理 Misfire 之前按租户过滤;领取后、真正触发前重新读取系统设置缓存。禁止仅在 `IJob.Execute`、Listener veto 或业务 V8 入口 return:共享 Quartz 可能已经推进 NextFireTime,造成旧版漏执行。
|
|
51
|
+
- 集群故障恢复也不得清理停用租户的在途记录或创建其补偿触发器。Quartz 以故障节点为单位清理记录,所以同一故障节点混有被停用租户时,新版推迟该故障节点整组恢复,交给旧节点或关闭开关后处理;其它健康节点仍正常领取。
|
|
52
|
+
- 正常保存系统设置在事务提交后失效缓存,下一次调度检查生效,不用重启;不是强制中断,已经开始的任务允许完成。缓存/配置读取失败拒绝该租户的新领取,不影响其它健康租户;Redis/失效通知异常时不能承诺硬实时。
|
|
53
|
+
- 停用期间只读观察周期计划,不推进共享触发器;每个“租户 + Job + Trigger + 计划时间”持久化确定性事件,包含 `Status=Skipped`、`Executed=false`、`Reason=SystemTaskSchedulingDisabled` 和中文说明。Redis 原子预留与日志确定性主键共同防止多新版节点重复记录;日志说明仅代表新版未执行,旧版仍可能正常执行。不补跑业务、不补写进程停机历史;新增/修改计划的日志目录最多约 10 秒更新。
|
|
54
|
+
- 普通接口调用、MQ 消费、升级/应用安装等持久后台任务不属于此开关的范围。手动触发 Quartz 任务仍经过门禁。
|
|
55
|
+
- 交付顺序:先安装字段并打开开关,再让新版节点参与调度;确认旧版所有调度进程已停止且在途任务完成后,关闭开关交接。不同业务库分别设置,不能用一个租户的值控制全部租户。
|
|
56
|
+
- 验收至少覆盖:默认兼容、开关实时读取、租户隔离、共享库旧节点继续领取、领取后开关变化不推进触发器、Misfire 不误推进、多节点日志去重;不得在真实生产任务上制造副作用做测试。
|
|
57
|
+
|
|
58
|
+
每个任务必须同时具备:
|
|
59
|
+
|
|
60
|
+
1. 分布式租约:Key 至少含 `OsClient + JobKey + 计划时间/业务分片`,有唯一持有者、TTL、续租和仅持有者释放。
|
|
61
|
+
2. 业务幂等:稳定 `IdempotencyKey/EventId`、数据库唯一约束或条件状态迁移。
|
|
62
|
+
3. 可恢复状态:待处理、处理中、成功、失败、下次重试时间写共享数据库/Redis/MQ。
|
|
63
|
+
4. fencing:锁可能过期的资金、库存等任务使用版本号/条件更新拒绝旧持有者写入。
|
|
64
|
+
|
|
65
|
+
锁只能减少并发,不能替代幂等。
|
|
66
|
+
|
|
67
|
+
## 任务骨架
|
|
68
|
+
|
|
69
|
+
```js
|
|
70
|
+
// 接口引擎由 Job 调用;JobRunId/FireTime 由调度层传入
|
|
71
|
+
var idempotencyKey = String(V8.Param.JobRunId || '');
|
|
72
|
+
if (!idempotencyKey) return { Code: 0, Msg: '缺少 JobRunId' };
|
|
73
|
+
|
|
74
|
+
// 推荐调用专用后端能力,以唯一约束抢占执行记录
|
|
75
|
+
var claim = V8.FormEngine.AddFormData('job_execution', {
|
|
76
|
+
JobKey: 'daily_order_summary',
|
|
77
|
+
IdempotencyKey: idempotencyKey,
|
|
78
|
+
Status: 'Running'
|
|
79
|
+
});
|
|
80
|
+
if (claim.Code !== 1) return { Code: 1, Msg: '已执行或正在执行' };
|
|
81
|
+
|
|
82
|
+
// 分页处理;每个业务副作用仍需自己的幂等键
|
|
83
|
+
return { Code: 1, Data: { IdempotencyKey: idempotencyKey } };
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
实际项目优先由数据库唯一索引和接口引擎事务完成抢占,不能仅用“先查再新增”。该唯一索引必须声明在 Manifest `tables[].indexes`,并用 `microi_create_table_index` 创建、`microi_get_table_indexes` 回读;禁止在 Job/V8 内手写 `CREATE INDEX`。任务扫描还应按实际 SQL 建立 `(OsClient, Status, NextRetryTime)` 或 `(OsClient, JobKey, ScheduleTime)` 等组合索引。
|
|
87
|
+
|
|
88
|
+
## 失败、重试与停机
|
|
89
|
+
|
|
90
|
+
- 先证明任务真的在执行:读 `Scheduler.IsStarted`、`Scheduler.NumberOfJobsExecuted` 和 `Acquisition.LastAcquisitionError`,参考 `microi.doc/docs/doc/system-engine/job.md` 的“任务不执行”。`diy_schedule_job.Status=正常`、`diy_schedule_job.NextTime` 和“插件启动成功”都不能证明触发成功;列表/详情页的 `LastTime/NextTime` 来自运行时,直接查表看到的是库内快照。
|
|
91
|
+
- 领取错误含 `Key 'IDX_microi_job_T_NFT_ST' doesn't exist` 时,是 Quartz 3.19 MySQL 方言依赖 `USE INDEX (IDX_{tablePrefix}T_NFT_ST)` 与 `IDX_{tablePrefix}T_NFT_ST_MISFIRE`,而触发器表缺少这两个索引(常见于历史租户库仍是旧 `QRTZ_` 前缀索引名)。平台调度器初始化会按前缀幂等补齐;人工抢修可直接执行文档中的两条 `CREATE INDEX`,索引名大小写不敏感,补完后无需重建任务或 Cron。
|
|
92
|
+
- 失败记录错误分类、重试次数和 `NextRetryTime`,采用有上限退避;永久错误进入人工处理。
|
|
93
|
+
- 外部调用设置超时;无法确认对方是否成功时用业务幂等号查询,不盲目重发。
|
|
94
|
+
- 服务停机先停止接单,再在有限宽限期排空或持久化;重启扫描未完成任务。
|
|
95
|
+
- 若要求 `kill -9` 前也零丢失,业务成功响应前必须获得共享 outbox/MQ/WAL 持久化确认。
|
|
96
|
+
|
|
97
|
+
## 后台按钮
|
|
98
|
+
|
|
99
|
+
满足任一条件即按后台任务设计:预计超过 2 分钟、500 条以上、1000 个以上扇出子操作、100 次以上外部调用、总量未知且可能持续运行,或安装/初始化/批量导入/批量生成/全量同步/迁移/备份。预计超过 10 分钟时,仅设置 `RunBackground=true` 仍不够,必须按 checkpoint 分片,每片独立事务。
|
|
100
|
+
|
|
101
|
+
菜单按钮设置 `RunBackground/BackgroundTask/IsBackgroundTask=true` 和 `ApiEngineKey`,并配置 `BackgroundTaskOptions`:
|
|
102
|
+
|
|
103
|
+
- `IdempotencyKey` 或 `IdempotencyKeyFields`:跨节点、重试和重复点击保持稳定。
|
|
104
|
+
- `ConcurrencyKey`:DDL、安装等不能并行的工作使用同一租约组。
|
|
105
|
+
- `BusinessTable + BusinessId`:关联业务记录。
|
|
106
|
+
- `BusinessStatusField + BusinessTaskIdField`:业务记录至少标记“后台处理中”和任务 Id;推荐再配置 `BusinessProgressField + BusinessEtaField`。
|
|
107
|
+
|
|
108
|
+
按钮提交成功后,平台前端会通过当前用户的 `V8.FormEngine` 权限把业务记录标记为“后台处理中”并写入任务 Id;后台服务不能直接相信客户端字段名而绕过表单权限。接口引擎仍必须在最后一片或异常补偿中把该业务记录改成“已完成 / 失败 / 已取消”,并保留任务 Id 供详情追溯:
|
|
109
|
+
|
|
110
|
+
```js
|
|
111
|
+
var task = V8.Param._BackgroundTask || {};
|
|
112
|
+
if (task.BusinessTable && task.BusinessId) {
|
|
113
|
+
var patch = { Id: task.BusinessId };
|
|
114
|
+
patch[task.BusinessStatusField] = '后台处理中';
|
|
115
|
+
patch[task.BusinessTaskIdField] = task.Id;
|
|
116
|
+
V8.FormEngine.UptFormData(task.BusinessTable, patch);
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
不得让通用后台服务按客户端传入的任意表名/字段名直接写库;需要脱离前端自动标记的专用任务,应在受控接口引擎中使用固定表名和固定字段名。
|
|
121
|
+
|
|
122
|
+
接口通过 `V8.Method.UpdateBackgroundTask({Current,Total,Msg,Log})` 上报已提交的真实工作量,`Log`/`AppendLog` 用于追加任务详情(不得包含密码、Token 或密钥)。平台按实际吞吐计算 `EstimatedEndTime`;总量未知时不传 `Total`,通知中心显示“不定进度/估算中”,禁止用固定 10%、阶段占位或计时器伪造进度。失败和取消停在最后真实进度,不得显示 100%。
|
|
123
|
+
|
|
124
|
+
分片接口在仍有后续工作时返回:
|
|
125
|
+
|
|
126
|
+
```js
|
|
127
|
+
return {
|
|
128
|
+
Code: 1,
|
|
129
|
+
Data: {
|
|
130
|
+
BackgroundTask: {
|
|
131
|
+
HasMore: true,
|
|
132
|
+
Checkpoint: { LastId: lastId },
|
|
133
|
+
Current: committedCount,
|
|
134
|
+
Total: totalCount,
|
|
135
|
+
NextDelaySeconds: 1,
|
|
136
|
+
Msg: '本批已提交,等待下一批'
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
最后一片返回普通 `Code:1`。每个业务副作用还要用 `_BackgroundTaskIdempotencyKey + 业务行Id` 建唯一约束;`_BackgroundTaskFencingToken` 用于拒绝租约过期旧执行者的写入。
|
|
143
|
+
|
|
144
|
+
## 长任务的 Jint 预算
|
|
145
|
+
|
|
146
|
+
后台 Worker 最终仍调用接口引擎,因此每个执行片段都受 `Timeout`、`MaxStatements`、单层累计分配预算、根调用树累计分配预算、JavaScript 递归和接口嵌套深度限制。`LimitMemory=2048` 表示当前片段累计分配了多少托管字节,不表示实时占用或预留 2GB 物理内存。
|
|
147
|
+
|
|
148
|
+
- 总任务运行 10 分钟、30 分钟或数小时是允许的;单个连续 Jint 调用不应承担全部时长。
|
|
149
|
+
- 每片在预算内提交事务并返回 `HasMore + Checkpoint`;Worker 重新入队后会创建新的 Jint Engine,新片重新获得超时、语句和累计分配预算。
|
|
150
|
+
- `V8.ApiEngine.Run` 的多层编排可以保留。新版父子单层分配隔离后,子接口不会被所有祖先重复计费,但根调用树仍有整体预算;循环调用由独立的嵌套深度上限终止。
|
|
151
|
+
- 捕获失败时读取 `DataAppend.V8Limit.Code`。内存/调用树/语句/超时分别缩小批次,递归错误修复函数递归,嵌套深度错误检查循环编排;不要统一归因于服务器资源不足。
|
|
152
|
+
- 可记录 `V8.Limits` 到脱敏诊断日志,但不要在每条业务数据上重复输出。
|
|
153
|
+
- 接口引擎和表后端事件分别使用正向 `sys_apiengine.V8Limit`、`diy_table.V8Limit`;二者默认 `0`,不设置 Jint 单片预算,只有明确需要限制单片时才设为 `1` 并配置超时、语句、分配和递归值。后台任务仍优先 `HasMore + Checkpoint`,因为不限 Jint 预算不等于数据库长事务、进程常驻内存、取消、并发或节点故障风险消失。
|
|
154
|
+
|
|
155
|
+
## MCP 工作流
|
|
156
|
+
|
|
157
|
+
1. 读取表、接口引擎和现有任务。
|
|
158
|
+
2. 先设计幂等键、状态机、租约和补偿。
|
|
159
|
+
3. `microi_save_job` 保存任务,写入需明确确认。
|
|
160
|
+
4. 回读任务 cron、启用状态、Key、接口引擎。
|
|
161
|
+
5. 两节点同时触发、重复投递、持有者中止、Redis 故障和滚动升级验收。
|
|
162
|
+
|
|
163
|
+
## 验收清单
|
|
164
|
+
|
|
165
|
+
- [ ] 任务配置仅管理员可改
|
|
166
|
+
- [ ] 两节点同一时刻触发,业务副作用仅一次
|
|
167
|
+
- [ ] 重复消息/请求不会重复扣减或生成流水
|
|
168
|
+
- [ ] 锁持有者退出后可恢复,无永久死锁
|
|
169
|
+
- [ ] 失败可重试、可追踪、可人工补偿
|
|
170
|
+
- [ ] 新旧版本滚动共存,状态和消息合约兼容
|
|
171
|
+
- [ ] 未知总量不显示假百分比;已知总量由 Current/Total 唯一推导
|
|
172
|
+
- [ ] ETA 来自真实吞吐,样本不足时明确显示“估算中”
|
|
173
|
+
- [ ] 业务记录可通过 BackgroundTaskId 跳转通知中心排查
|
|
174
|
+
- [ ] 超过 10 分钟的任务有 checkpoint,重启后从最后已提交批次恢复
|
|
175
|
+
- [ ] 单片低于超时/语句/累计分配预算,任务总时长不依赖放大单次接口上限
|
|
176
|
+
- [ ] 嵌套接口没有循环调用,且错误日志包含结构化 `V8Limit` 分类和调用路径
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
interface:
|
|
2
|
-
display_name: "任务引擎"
|
|
3
|
-
short_description: "设计可幂等、可恢复并适用于多节点滚动部署的定时与后台任务"
|
|
4
|
-
default_prompt: "使用 $job-engine 设计并验收当前 Microi 定时或后台任务。"
|
|
1
|
+
interface:
|
|
2
|
+
display_name: "任务引擎"
|
|
3
|
+
short_description: "设计可幂等、可恢复并适用于多节点滚动部署的定时与后台任务"
|
|
4
|
+
default_prompt: "使用 $job-engine 设计并验收当前 Microi 定时或后台任务。"
|