1 定时任务系统(api/schedule)--- 模块概述
1.1 模块定位
api/schedule/ 是 Dify 的定时任务中枢 ,基于 Celery Beat 调度器定义所有周期性后台任务。
每个文件对应一个独立的 Celery 任务,通过 api/extensions/ext_celery.py 中的 beat_schedule 注册触发频率,并由功能开关(dify_config.ENABLE_*)控制是否激活。
代码路径:api/schedule/
调度注册:api/extensions/ext_celery.py → init_app()
1.2 架构概览
Celery Beat (定时触发)
│
├─ crontab / timedelta 表达式
│
▼
beat_schedule (ext_celery.py)
│ 按配置开关动态注册
▼
schedule/*.py (各任务定义)
│
├─ 直接操作 DB / Redis
└─ 或 .delay() → Celery Worker Queue (异步子任务)
所有任务均以 @app.celery.task(queue="<queue_name>") 装饰,队列名与 Worker 配置对应,保证资源隔离。
1.3 任务全景
| 任务函数 | 文件 | 队列 | 默认调度周期 | 分类 |
|---|---|---|---|---|
clean_embedding_cache_task |
clean_embedding_cache_task.py |
dataset |
每 N 天 02:00 | 数据清理 |
clean_unused_datasets_task |
clean_unused_datasets_task.py |
dataset |
每 N 天 03:00 | 数据清理 |
clean_messages |
clean_messages.py |
retention |
每 N 天 04:00 | 数据清理 |
clean_workflow_runs_task |
clean_workflow_runs_task.py |
retention |
每天 00:00 | 数据清理 |
clean_workflow_runlogs_precise |
clean_workflow_runlogs_precise.py |
retention |
每天 02:00 | 数据清理 |
mail_clean_document_notify_task |
mail_clean_document_notify_task.py |
dataset |
每周一 10:00 | 通知 |
queue_monitor_task |
queue_monitor_task.py |
monitor |
每 30 分钟 | 运维监控 |
check_upgradable_plugin_task |
check_upgradable_plugin_task.py |
plugin |
每 15 分钟 | 插件管理 |
poll_workflow_schedules |
workflow_schedule_task.py |
schedule_poller |
可配置(分钟级) | Workflow 触发 |
trigger_provider_refresh |
trigger_provider_refresh_task.py |
trigger_refresh_publisher |
可配置(分钟级) | 触发器管理 |
create_tidb_serverless_task |
create_tidb_serverless_task.py |
dataset |
每小时整点 | TiDB 资源管理 |
update_tidb_serverless_status_task |
update_tidb_serverless_status_task.py |
dataset |
每 10 分钟 | TiDB 资源管理 |
batch_update_api_token_last_used |
update_api_token_last_used_task.py |
api_token |
每 30 分钟 | Token 管理 |
1.4 任务分类说明
1.4.1 数据清理类(Retention)
定期删除过期数据,防止数据库无限膨胀。包含嵌入缓存、知识库索引、消息记录、Workflow 运行日志等。部分任务通过 Redis 分布式锁防止并发执行。
1.4.2 通知类(Notification)
在数据清理后向租户发送邮件通知(如知识库文档被自动禁用)。
1.4.3 运维监控类(Monitoring)
监控 Celery 队列积压情况,超阈值时发送告警邮件。
1.4.4 插件管理类(Plugin)
定期检查哪些插件有可用更新,并按租户策略自动触发升级检查任务。
1.4.5 Workflow 定时触发类(Scheduling)
轮询 WorkflowSchedulePlan 表中到期的调度计划,分批派发给 Celery Worker 执行。
1.4.6 触发器凭证刷新类(Trigger)
扫描即将过期的触发器订阅(Webhook/外部事件),在到期前批量刷新凭证。
1.4.7 TiDB Serverless 资源池管理(Cloud)
维护 TiDB Serverless 集群的空闲资源池(按需创建和状态同步)。
1.4.8 API Token 使用记录类(Token)
将 Redis 中的 API Token 最近使用时间批量刷新到数据库,避免每次请求写 DB 的热点问题。
1.5 关键设计模式
1.5.1 功能开关 + 动态注册
python
# ext_celery.py
if dify_config.ENABLE_CLEAN_EMBEDDING_CACHE_TASK:
imports.append("schedule.clean_embedding_cache_task")
beat_schedule["clean_embedding_cache_task"] = {...}
所有任务均受配置开关保护,生产环境可按需启禁,不影响其他服务。
1.5.2 Redis 分布式锁防并发
python
with redis_client.lock("retention:clean_messages", timeout=..., blocking=False):
...
clean_messages 和 clean_workflow_runs_task 使用非阻塞锁:若已有实例在运行,当前调用直接跳过,避免重叠执行。
1.5.3 批次分页 + 增量游标
数据量大的清理任务(如 clean_workflow_runlogs_precise)使用 last_seen 游标分批处理,单批失败不影响已处理批次,支持重试。
1.5.4 子任务 Fanout(异步派发)
check_upgradable_plugin_task 和 poll_workflow_schedules 将实际工作通过 .delay() / group() 派发给独立 Worker,自身只做调度协调,快速返回。
1.6 依赖关系
1.6.1 被以下模块依赖
api/extensions/ext_celery.py:注册并启动所有定时任务
1.6.2 依赖以下模块
| 依赖模块 | 用途 |
|---|---|
extensions/ext_database |
数据库操作(增删查改) |
extensions/ext_redis |
分布式锁、Redis 缓存读写 |
extensions/ext_mail |
发送告警/通知邮件 |
services/retention/ |
数据保留策略与清理服务 |
tasks/process_tenant_plugin_autoupgrade_check_task |
子任务:租户插件升级检查 |
tasks/workflow_schedule_tasks |
子任务:运行 Schedule Trigger |
tasks/trigger_subscription_refresh_tasks |
子任务:刷新触发器订阅 |
core/rag/index_processor/ |
清理向量索引(知识库) |
core/helper/marketplace |
获取全局插件 Manifest |
models/ |
DB 模型(Dataset、Embedding、WorkflowRun 等) |

2 数据清理定时任务详解
2.1 概述
数据清理任务负责定期删除 Dify 中的过期数据,防止数据库无限膨胀。涉及五类数据:
| 任务 | 目标数据 | 触发时间 |
|---|---|---|
clean_embedding_cache_task |
过期 Embedding 缓存(embeddings 表) |
每 N 天 02:00 |
clean_unused_datasets_task |
长期未访问的知识库向量索引 | 每 N 天 03:00 |
clean_messages |
过期对话消息记录 | 每 N 天 04:00 |
clean_workflow_runs_task |
Sandbox 租户过期 Workflow 运行记录 | 每天 00:00 |
clean_workflow_runlogs_precise |
精确清理过期 Workflow 运行日志(全量) | 每天 02:00 |
N由CELERY_BEAT_SCHEDULER_TIME配置;消息/Workflow 保留天数由各自*_RETENTION_DAYS配置控制。
2.2 clean_embedding_cache_task
文件 :api/schedule/clean_embedding_cache_task.py
队列 :dataset
2.2.1 逻辑
- 读取
PLAN_SANDBOX_CLEAN_DAY_SETTING确定保留天数,计算截止时间thirty_days_ago - 循环:每批查询 100 条早于截止时间的
Embedding记录 ID - 逐条
DELETE FROM embeddings WHERE id = :id commit(),无记录时退出循环
2.2.2 特点
- 纯数据库逐条删除,简单直接
- 无分布式锁(任务幂等,重复执行无害)
2.3 clean_unused_datasets_task
文件 :api/schedule/clean_unused_datasets_task.py
队列 :dataset
2.3.1 逻辑
执行两组清理配置(Sandbox 和 Pro 计划各一份):
for config in [sandbox_config, pro_config]:
分页查询满足以下条件的 Dataset:
- 创建时间 < 截止日期
- 无新文档(截止日期后无更新的已启用文档)
- 有旧文档(截止日期前有已启用文档)
for dataset in page:
if 截止日期后无查询记录(DatasetQuery):
if 满足 plan_filter:
删除向量索引(IndexProcessorFactory.clean)
批量 UPDATE documents SET enabled=False
可选:记录 DatasetAutoDisableLog
2.3.2 特点
- 双重条件判断:时间维度(文档更新时间)+ 使用维度(DatasetQuery 查询记录)
- 通过
FeatureService+ Redis 缓存(600s TTL)查询租户计划,避免频繁调用 - 分页处理(每页 50 条),防止大查询超时
2.4 clean_messages
文件 :api/schedule/clean_messages.py
队列 :retention
2.4.1 逻辑
创建 MessagesCleanPolicy(根据 BILLING_ENABLED)
with redis_client.lock("retention:clean_messages", blocking=False):
MessagesCleanService.from_days(policy, days, batch_size).run()
2.4.2 计费区分逻辑
BILLING_ENABLED=True:仅删除 Sandbox 租户的消息(含白名单/宽限期)BILLING_ENABLED=False:删除所有超期消息
2.4.3 特点
- 非阻塞分布式锁:获取失败直接跳过,不阻塞后续调度
- 实际删除逻辑封装在
services/retention/conversation/中,职责分离
2.5 clean_workflow_runs_task
文件 :api/schedule/clean_workflow_runs_task.py
队列 :retention
2.5.1 逻辑
with redis_client.lock("retention:clean_workflow_runs_task", blocking=False):
WorkflowRunCleanup(days, batch_size).run()
- 仅清理 Sandbox 租户的过期 Workflow 运行记录(SaaS 专用)
- 实际级联删除逻辑封装在
services/retention/workflow_run/中
2.5.2 特点
- 同样使用非阻塞分布式锁防并发
- 与
clean_workflow_runlogs_precise的区别:前者针对 Sandbox 计划租户,后者精确模式支持全量清理并可指定特定 Workflow
2.6 clean_workflow_runlogs_precise
文件 :api/schedule/clean_workflow_runlogs_precise.py
队列 :retention
2.6.1 逻辑(精确级联删除)
while True:
batch = workflow_run_repo.get_runs_batch_by_time_range(
end_before=cutoff_date,
last_seen=last_seen, # 增量游标
batch_size=BATCH_SIZE,
workflow_ids=filter # 可选:仅清理指定 Workflow
)
if not batch: break
with session.begin():
_delete_batch(session, batch) # 嵌套事务
last_seen = (batch[-1].created_at, batch[-1].id)
_delete_batch 的级联删除顺序:
- 查出
Message.id和Conversation.id(关联 WorkflowRun) - 删除 Message 附属表(
MessageAgentThought、MessageFile、MessageAnnotation等 8 张表) - 删除
Message - 删除
ConversationVariable→Conversation - 删除
WorkflowNodeExecution(通过 Repository) - 删除
WorkflowTriggerLog(通过 Repository) - 删除
WorkflowRun本体
2.6.2 特点
- 增量游标 :
last_seen=(created_at, id)保证分批不重不漏 - 嵌套事务 :
session.begin_nested()保证单批原子性 - 重试机制:失败后 5/10/15 分钟递增等待,最多重试 3 次
- 可指定 Workflow :
WORKFLOW_LOG_CLEANUP_SPECIFIC_WORKFLOW_IDS支持针对特定 Workflow 清理
2.7 时序图


3 Workflow 定时调度轮询任务详解
3.1 概述
poll_workflow_schedules(api/schedule/workflow_schedule_task.py)是 Dify Workflow Schedule Trigger 功能的核心调度器。
它以可配置的分钟间隔运行,从 WorkflowSchedulePlan 表中批量取出到期的调度计划,更新下次执行时间,并通过 Celery group() 并行派发执行任务。
文件 :api/schedule/workflow_schedule_task.py
队列 :schedule_poller
调度周期 :timedelta(minutes=WORKFLOW_SCHEDULE_POLLER_INTERVAL)(默认可配置)
功能开关 :ENABLE_WORKFLOW_SCHEDULE_POLLER_TASK
3.2 核心数据模型
| 模型 | 表 | 作用 |
|---|---|---|
WorkflowSchedulePlan |
workflow_schedule_plans |
每个 Schedule 节点的执行计划(下次运行时间、cron 表达式、时区) |
AppTrigger |
app_triggers |
应用触发器注册(关联 AppId + NodeId,含状态 ENABLED/DISABLED) |
3.3 执行流程
poll_workflow_schedules()
│
├─ 创建 Session
│
└─ loop:
├─ _fetch_due_schedules(session)
│ SELECT WorkflowSchedulePlan
│ JOIN AppTrigger ON (app_id, node_id, type=SCHEDULE)
│ WHERE next_run_at <= now
│ AND AppTrigger.status = ENABLED
│ ORDER BY next_run_at ASC ← 最久未执行优先
│ FOR UPDATE SKIP LOCKED ← 多实例安全
│ LIMIT WORKFLOW_SCHEDULE_POLLER_BATCH_SIZE
│
├─ if no due_schedules: break
│
├─ _process_schedules(session, due_schedules, producer)
│ for each schedule:
│ next_run_at = calculate_next_run_at(cron, timezone)
│ schedule.next_run_at = next_run_at ← 立即更新,防止重入
│ group([run_schedule_trigger.s(id) for id in ids]).apply_async()
│ session.commit()
│
└─ 检查熔断器:total_dispatched >= MAX_DISPATCH_PER_TICK → break
3.4 关键设计
3.4.1 SELECT FOR UPDATE SKIP LOCKED
多个 Beat 实例并发时,FOR UPDATE SKIP LOCKED 保证同一条 WorkflowSchedulePlan 只被一个实例处理,无需额外分布式锁。
3.4.2 先更新 next_run_at 再派发
在派发 Celery 任务之前 先 commit 更新 next_run_at,即使 Worker 执行失败,下次轮询也不会重复触发同一计划(时间窗口内最多一次语义)。
3.4.3 熔断器(Circuit Breaker)
python
if 0 < dify_config.WORKFLOW_SCHEDULE_MAX_DISPATCH_PER_TICK <= total_dispatched:
break # 本轮停止,下轮继续
防止单轮派发任务数爆炸(如系统积压大量到期任务时)。
3.4.4 Celery group() 并行派发
同一批次的调度任务通过 group() 以单次 broker 事务发送,降低多次 round-trip 的延迟。
3.5 时序图

3.6 配置参数
| 参数 | 说明 |
|---|---|
ENABLE_WORKFLOW_SCHEDULE_POLLER_TASK |
任务开关 |
WORKFLOW_SCHEDULE_POLLER_INTERVAL |
轮询间隔(分钟) |
WORKFLOW_SCHEDULE_POLLER_BATCH_SIZE |
每批取出的最大调度计划数 |
WORKFLOW_SCHEDULE_MAX_DISPATCH_PER_TICK |
单轮最大派发数(熔断阈值,0=不限) |

4 插件自动升级检查任务详解
4.1 概述
check_upgradable_plugin_task(api/schedule/check_upgradable_plugin_task.py)负责定期检查各租户的插件是否有可用更新,并根据租户的自动升级策略触发升级操作。
文件 :api/schedule/check_upgradable_plugin_task.py
队列 :plugin
调度周期 :每 15 分钟(crontab(minute="*/15"))
功能开关 :ENABLE_CHECK_UPGRADABLE_PLUGIN_TASK + MARKETPLACE_ENABLED
4.2 核心数据模型
| 模型 | 作用 |
|---|---|
TenantPluginAutoUpgradeStrategy |
租户插件自动升级配置(升级时间段、策略、排除/包含列表) |
4.3 执行流程
check_upgradable_plugin_task()
│
├─ 计算 now_seconds_of_day(当天已过秒数)
│
├─ 查询 TenantPluginAutoUpgradeStrategy
│ WHERE upgrade_time_of_day IN [now, now+15min)
│ AND strategy_setting != DISABLED
│
├─ if 无策略: return(跳过 Marketplace 请求,节省流量)
│
├─ fetch_global_plugin_manifest(cache_prefix, cache_ttl)
│ ← 一次性获取所有插件的最新版本信息并缓存到 Redis
│ ← 从 30万次请求 → 每轮 1 次请求
│
└─ 分批派发(每批最多 MAX_CONCURRENT_CHECK_TASKS=20):
for i in range(0, total, 20):
for strategy in batch:
process_tenant_plugin_autoupgrade_check_task.delay(
tenant_id, strategy_setting,
upgrade_time_of_day, upgrade_mode,
exclude_plugins, include_plugins
)
sleep(batch_interval_time) ← 批次间匀速派发
4.4 关键设计
4.4.1 时间窗口筛选(15 分钟粒度)
租户可以配置"每天几点进行升级检查"(upgrade_time_of_day)。调度器每 15 分钟运行一次,每次只处理"升级时间恰好落在当前 15 分钟窗口内"的租户,避免所有租户同时处理。
4.4.2 全局 Manifest 缓存
python
fetch_global_plugin_manifest(CACHE_REDIS_KEY_PREFIX, CACHE_REDIS_TTL)
在处理租户前,先将整个 Marketplace 的插件 Manifest 一次性拉取并缓存到 Redis。每个租户的子任务直接读 Redis 缓存,将 Marketplace API 的请求压力从 O(租户数) 降低到 O(1)。
4.4.3 匀速批次派发(流量整形)
python
batch_interval_time = AUTO_UPGRADE_MINIMAL_CHECKING_INTERVAL / batch_chunk_count
time.sleep(batch_interval_time) # 仅在非最后一批时 sleep
将所有策略在 15 分钟内匀速分批派发,避免瞬间涌入大量子任务挤压 plugin 队列。
4.5 时序图

4.6 配置参数
| 参数 | 说明 |
|---|---|
ENABLE_CHECK_UPGRADABLE_PLUGIN_TASK |
任务开关 |
MARKETPLACE_ENABLED |
市场功能开关(双重保障) |
AUTO_UPGRADE_MINIMAL_CHECKING_INTERVAL |
检查窗口大小(硬编码 900s/15min) |
MAX_CONCURRENT_CHECK_TASKS |
每批最大并发子任务数(硬编码 20) |
5 API Token 使用时间批量刷新任务详解
5.1 概述
batch_update_api_token_last_used(api/schedule/update_api_token_last_used_task.py)将 Redis 中暂存的 API Token 最近使用时间批量写回数据库,实现写延迟聚合,避免每次 API 请求都触发数据库写操作。
文件 :api/schedule/update_api_token_last_used_task.py
队列 :api_token
调度周期 :timedelta(minutes=API_TOKEN_LAST_USED_UPDATE_INTERVAL)(默认 30 分钟)
功能开关 :ENABLE_API_TOKEN_LAST_USED_UPDATE_TASK
5.2 设计背景
每次 API 请求时,若直接 UPDATE api_tokens SET last_used_at=now,在高频调用场景下会产生大量数据库写热点。
解决方案:
- 请求时 :仅在 Redis 记录一个
api_token_active:{scope}:{token}键,值为 ISO 格式时间戳,TTL 覆盖至下次刷新 - 定时任务:批量扫描 Redis 键,写回数据库后删除 Redis 键
5.3 Redis Key 格式
api_token_active:{scope}:{token_value}
scope:Token 类型(如app、dataset,或None)token_value:实际 Token 字符串value:最近使用时间(ISO 8601 格式)
5.4 执行流程
batch_update_api_token_last_used()
│
├─ redis_client.scan_iter("api_token_active:*", count=200)
│ ← 增量扫描,不阻塞 Redis
│
├─ for each key:
│ ├─ GET value(ISO 时间戳)
│ ├─ 解析 scope 和 token
│ └─ 加入 token_entries[]
│
├─ if token_entries 为空: 清理无效键后 return
│
├─ for each (token, scope, usage_time):
│ UPDATE api_tokens
│ SET last_used_at = usage_time
│ WHERE token = token
│ AND type = scope
│ AND (last_used_at IS NULL OR last_used_at < usage_time)
│ ← 条件更新:只在新时间更晚时才写
│
└─ redis_client.delete(*keys_to_delete) ← 清理已处理的 Redis 键
5.5 关键设计
5.5.1 scan_iter 非阻塞扫描
使用 SCAN 而非 KEYS 命令,每次返回部分结果,不阻塞 Redis 服务。
5.5.2 条件更新防回退
python
WHERE last_used_at IS NULL OR last_used_at < usage_time
若同一 Token 在扫描期间再次被使用(新键已写入),旧的 usage_time 不会覆盖更新的时间。
5.5.3 短事务设计
每个 Token 单独开一个短 Session + BEGIN/COMMIT,避免长事务持有锁:
python
with Session(db.engine) as session, session.begin():
session.execute(update(ApiToken).where(...).values(...))
5.5.4 先写 DB,后删 Redis
保证在 Redis 键被删除前数据已落库,避免数据丢失。
5.6 配置参数
| 参数 | 说明 |
|---|---|
ENABLE_API_TOKEN_LAST_USED_UPDATE_TASK |
任务开关 |
API_TOKEN_LAST_USED_UPDATE_INTERVAL |
刷新间隔(分钟) |
ACTIVE_TOKEN_KEY_PREFIX |
Redis key 前缀(定义于 services/api_token_service.py) |

6 其他定时任务详解
6.1 触发器订阅凭证刷新(trigger_provider_refresh)
文件 :api/schedule/trigger_provider_refresh_task.py
队列 :trigger_refresh_publisher
功能开关 :ENABLE_TRIGGER_PROVIDER_REFRESH_TASK
调度周期 :timedelta(minutes=TRIGGER_PROVIDER_REFRESH_INTERVAL)
6.1.1 功能
扫描 TriggerSubscription 表,找出凭证(credential)或订阅(subscription) 即将到期的记录,批量刷新以维持 Webhook/外部事件触发器的持续可用性。
6.1.2 流程
trigger_provider_refresh()
│
├─ filter = (credential_expires_at <= now + CREDENTIAL_THRESHOLD) OR
│ (expires_at <= now + SUBSCRIPTION_THRESHOLD)
│
├─ count = SELECT COUNT WHERE filter
├─ if count == 0: return
│
└─ 分页处理:
for page in pages:
rows = SELECT (tenant_id, subscription_id) WHERE filter
ORDER BY updated_at ASC LIMIT batch_size
lock_keys = build_trigger_refresh_lock_keys(rows)
acquired = Redis PIPELINE SETNX(lock_keys, ttl=lock_ttl) ← 原子批量加锁
jobs = [refresh.s(t, s) for (t,s), locked in zip if locked]
group(jobs).apply_async()
6.1.3 关键设计
- 原子批量加锁 :通过 Redis Pipeline
SETNX一次性获取多个锁,避免同一订阅被重复刷新 - TTL 与阈值挂钩 :锁的 TTL =
max(300, SUBSCRIPTION_THRESHOLD_SECONDS),确保刷新完成前锁不过期 - 排序策略 :
ORDER BY updated_at ASC优先处理最长时间未刷新的订阅
6.2 队列积压监控(queue_monitor_task)
文件 :api/schedule/queue_monitor_task.py
队列 :monitor
功能开关 :ENABLE_DATASETS_QUEUE_MONITOR
调度周期 :timedelta(minutes=QUEUE_MONITOR_INTERVAL)(默认 30 分钟)
6.2.1 功能
监控 dataset Celery 队列的积压长度,超过阈值时向配置的邮件列表发送告警。
6.2.2 流程
queue_monitor_task()
│
├─ if QUEUE_MONITOR_THRESHOLD is None: 跳过
│
├─ celery_redis.llen("dataset") ← 直接读 Celery Broker Redis
│
├─ if queue_length >= threshold:
│ for email in QUEUE_MONITOR_ALERT_EMAILS:
│ send_email(QUEUE_MONITOR_ALERT, to=email, {queue_name, length, threshold, time})
│
└─ finally: close db.session
6.2.3 特点
- 直连 Celery Broker 的 Redis(使用独立 Redis 连接,非业务 Redis)
- 仅监控
dataset队列(知识库相关任务最容易积压) - 5s socket 超时 + 健康检查,防止长连接僵死
6.3 TiDB Serverless 资源池管理
6.3.1 3a. 集群创建(create_tidb_serverless_task)
文件 :api/schedule/create_tidb_serverless_task.py
队列 :dataset
调度周期 :每小时整点(crontab(minute="0", hour="*"))
功能开关 :ENABLE_CREATE_TIDB_SERVERLESS_TASK
功能:维持指定数量的空闲 TiDB Serverless 集群,供租户按需分配。
create_tidb_serverless_task()
│
├─ if not CREATE_TIDB_SERVICE_JOB_ENABLED: return
│
└─ while True:
idle_count = SELECT COUNT WHERE active=False
if idle_count >= TIDB_SERVERLESS_NUMBER: break
TidbService.batch_create_tidb_serverless_cluster(batch_size=20)
INSERT TidbAuthBinding(status=CREATING, active=False)
commit()
6.3.2 3b. 状态更新(update_tidb_serverless_status_task)
文件 :api/schedule/update_tidb_serverless_status_task.py
队列 :dataset
调度周期 :每 10 分钟(timedelta(minutes=10))
功能开关 :ENABLE_UPDATE_TIDB_SERVERLESS_STATUS_TASK
功能 :轮询处于 CREATING 状态的集群,通过 TiDB API 更新其最新状态(变为 ACTIVE 后可被租户使用)。
update_tidb_serverless_status_task()
│
├─ SELECT TidbAuthBinding WHERE active=False AND status=CREATING
├─ if 无记录: return
└─ 每批 20 个: TidbService.batch_update_tidb_serverless_cluster_status(items)
6.3.3 TiDB 资源池生命周期
[创建任务] → CREATING → [状态更新任务] → ACTIVE (active=False, 空闲)
↓ 租户分配
ACTIVE (active=True, 已使用)
6.4 文档清理邮件通知(mail_clean_document_notify_task)
文件 :api/schedule/mail_clean_document_notify_task.py
队列 :dataset
调度周期 :每周一 10:00(crontab(minute="0", hour="10", day_of_week="1"))
功能开关 :ENABLE_MAIL_CLEAN_DOCUMENT_NOTIFY_TASK
6.4.1 功能
clean_unused_datasets_task 清理知识库时会写入 DatasetAutoDisableLog。本任务读取未通知的日志,按租户聚合后向知识库 Owner 发送邮件告知哪些文档被自动禁用。
mail_clean_document_notify_task()
│
├─ if not mail.is_inited(): return
│
├─ SELECT DatasetAutoDisableLog WHERE notified=False
├─ 按 tenant_id 分组
│
└─ for tenant_id, logs in groups:
if plan == SANDBOX: skip(只通知付费用户)
找 owner 账号
聚合: {dataset_name: document_count}
send_email(DOCUMENT_CLEAN_NOTIFY, to=owner.email)
UPDATE notified=True
commit()
6.4.2 特点
- 只通知非 Sandbox 付费租户(Sandbox 用户无需通知)
- 每条日志只通知一次(
notified字段幂等保护) - 使用
EmailType.DOCUMENT_CLEAN_NOTIFY国际化邮件模板