定时任务设置
使用各种定时任务平台配置自动积分发放和过期处理
📋 概述
积分系统需要两个自动化定时任务才能正常运行:
- 发放积分任务 - 为订阅用户分发月度积分
- 过期积分任务 - 处理过期的积分批次
两个任务都必须配置为使用适当的身份验证调用您的 API 端点。
🔐 身份验证
所有定时任务请求必须在 Authorization 头中包含 CRON_SECRET
:
Authorization: Bearer your-cron-secret-here
生成 CRON_SECRET
生成一个安全的随机字符串(16+ 字符):
# 使用 OpenSSL
openssl rand -hex 16
# 使用 Node.js
node -e "console.log(require('crypto').randomBytes(16).toString('hex'))"
# 或使用任何密码生成器
添加到您的 .env
文件:
CRON_SECRET=a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6
🔄 定时任务端点
1. 发放积分端点
URL: https://yourdomain.com/api/jobs/credits/grant
用途: 为符合条件的用户发放月度订阅积分
计划: 每天 01:00 UTC(UTC 午夜)
HTTP 方法: GET
请求头:
Authorization: Bearer your-cron-secret
响应:
{
"success": true,
"jobId": "550e8400-e29b-41d4-a716-446655440000",
"date": "2024-01-15",
"duration": 1250,
"results": {
"processed": 150,
"successful": 148,
"skipped": 2,
"failed": 0
}
}
2. 过期积分端点
URL: https://yourdomain.com/api/jobs/credits/expire
用途: 处理过期的积分批次并更新余额
计划: 每天 04:00 UTC(UTC 凌晨 4 点)
HTTP 方法: GET
请求头:
Authorization: Bearer your-cron-secret
响应:
{
"success": true,
"jobId": "660e8400-e29b-41d4-a716-446655440001",
"duration": 850,
"results": {
"processedBatches": 45,
"processedUsers": 38,
"totalExpiredAmount": 1250
}
}
🚀 平台设置指南
选项 1:Vercel 定时任务
最适合: 部署在 Vercel 上的应用
设置步骤
- 在项目根目录创建
vercel.json
:
{
"crons": [
{
"path": "/api/jobs/credits/grant",
"schedule": "0 1 * * *"
},
{
"path": "/api/jobs/credits/expire",
"schedule": "0 4 * * *"
}
]
}
- 在 Vercel 中添加环境变量:
转到项目 → Settings → Environment Variables:
- Key:
CRON_SECRET
- Value:
your-generated-secret
- 部署更改:
git add vercel.json
git commit -m "Add cron jobs configuration"
git push
- 在 Vercel 控制面板中验证:
转到项目 → Deployments → Cron Jobs 查看活动任务。
Cron 计划格式:
0 1 * * *
= 每天 01:00 UTC0 4 * * *
= 每天 04:00 UTC
重要说明:
- ✅ 在 Vercel Pro 及以上计划中可用
- ✅ Vercel 自动身份验证
- ✅ 内置监控和日志
- ⚠️ 最大执行时间:10 秒(Hobby)、60 秒(Pro)、300 秒(Enterprise)
选项 2:Cloudflare 计划任务 Workers
最适合: 部署在 Cloudflare Pages/Workers 上的应用
设置步骤
- 在 Cloudflare 控制面板中创建新 Worker:
导航到 Workers & Pages → Create Worker
- 配置 Worker 代码:
// grant-credits-worker.js
export default {
async scheduled(event, env, ctx) {
const response = await fetch('https://yourdomain.com/api/jobs/credits/grant', {
method: 'GET',
headers: {
'Authorization': `Bearer ${env.CRON_SECRET}`,
},
});
const data = await response.json();
console.log('Grant credits job completed:', data);
},
};
- 添加 Cron 触发器:
在 Worker 设置 → Triggers → Cron Triggers:
- Schedule:
0 1 * * *
- 设置环境变量:
在 Worker 设置 → Variables:
- Variable name:
CRON_SECRET
- Value:
your-generated-secret
- 为过期积分任务重复操作:
创建另一个 Worker,计划为 0 1 * * *
,指向过期端点。
重要说明:
- ✅ 免费套餐可用,每天 100,000 次请求
- ✅ 全球边缘网络
- ✅ 可靠执行
- ⚠️ 每个定时任务需要单独的 Worker
选项 3:cron-job.org
最适合: 任何部署平台,设置简单
设置步骤
- 在 cron-job.org 注册
免费账户允许最多 50 个定时任务。
- 创建第一个定时任务(发放积分):
点击 "Create Cronjob" 并配置:
常规设置:
- Title:
Grant Monthly Credits
- Address:
https://yourdomain.com/api/jobs/credits/grant
- Request method:
GET
计划:
- Execution time:
01:00
(凌晨 1 点) - Timezone:
UTC
- Days: 每天
高级设置:
- HTTP Headers:
Authorization: Bearer your-cron-secret
通知:
- 启用失败的电子邮件通知(推荐)
- 创建第二个定时任务(过期积分):
重复配置:
- Title:
Expire Credits
- Address:
https://yourdomain.com/api/jobs/credits/expire
- Execution time:
04:00
- 保存并激活:
点击 "Create" 并确保状态显示为 "Enabled"。
重要说明:
- ✅ 提供免费套餐
- ✅ 失败的电子邮件通知
- ✅ 执行历史和日志
- ✅ 适用于任何平台
- ⚠️ 不如平台原生解决方案可靠
- ⚠️ 每个环境需要手动设置
选项 4:Upstash QStash
最适合: 现代无服务器应用,高可靠性
设置步骤
- 在 Upstash 注册
导航到 QStash 部分。
- 获取 QStash 令牌:
从控制面板复制您的 QStash Publishing Token。
- 创建计划请求:
使用 QStash API 或控制面板:
发放积分计划:
curl -X POST "https://qstash.upstash.io/v2/schedules" \
-H "Authorization: Bearer YOUR_QSTASH_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"destination": "https://yourdomain.com/api/jobs/credits/grant",
"cron": "0 1 * * *",
"headers": {
"Authorization": "Bearer your-cron-secret"
}
}'
过期积分计划:
curl -X POST "https://qstash.upstash.io/v2/schedules" \
-H "Authorization: Bearer YOUR_QSTASH_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"destination": "https://yourdomain.com/api/jobs/credits/expire",
"cron": "0 4 * * *",
"headers": {
"Authorization": "Bearer your-cron-secret"
}
}'
- 在 Upstash 控制面板中验证:
转到 QStash → Schedules 查看已配置的任务。
重要说明:
- ✅ 免费套餐:每天 500 条消息
- ✅ 内置重试和死信队列
- ✅ 优秀的可靠性
- ✅ 请求/响应日志
- ✅ 适用于任何平台
- ⚠️ 需要 API 设置
选项 5:GitHub Actions(不推荐用于生产环境)
最适合: 仅用于开发/测试
设置步骤
- 创建
.github/workflows/cron-jobs.yml
:
name: Credits Cron Jobs
on:
schedule:
# 每天 00:00 UTC 发放积分
- cron: '0 0 * * *'
# 每天 01:00 UTC 过期积分
- cron: '0 1 * * *'
workflow_dispatch: # 允许手动触发
jobs:
grant-credits:
if: github.event.schedule == '0 0 * * *'
runs-on: ubuntu-latest
steps:
- name: Grant Monthly Credits
run: |
curl -X GET "https://yourdomain.com/api/jobs/credits/grant" \
-H "Authorization: Bearer ${{ secrets.CRON_SECRET }}"
expire-credits:
if: github.event.schedule == '0 1 * * *'
runs-on: ubuntu-latest
steps:
- name: Expire Credits
run: |
curl -X GET "https://yourdomain.com/api/jobs/credits/expire" \
-H "Authorization: Bearer ${{ secrets.CRON_SECRET }}"
- 在 GitHub 中添加密钥:
Repository → Settings → Secrets → New repository secret:
- Name:
CRON_SECRET
- Value:
your-generated-secret
为何不推荐:
- ⚠️ 不太可靠(可能延迟或跳过)
- ⚠️ 需要公共仓库或 GitHub Pro
- ⚠️ 不适用于关键操作
- ⚠️ 可能有速率限制
🔍 监控和调试
检查定时任务执行
每个任务返回唯一的 jobId
用于追踪。监控应用日志:
# Vercel
vercel logs --follow
# Cloudflare
wrangler tail
# 检查应用日志:
[Credits Grant Job abc123] Starting daily grant process
[Credits Grant Job abc123] Completed in 1250ms. Processed: 150, Successful: 148
常见问题
1. 身份验证失败
错误: { "error": "Unauthorized" }
解决方案:
- 验证已设置
CRON_SECRET
环境变量 - 检查 Authorization 头格式:
Bearer your-secret
- 确保密钥中没有额外的空格或换行符
2. 任务超时
错误: 任务超时或返回 504
解决方案:
- 在平台设置中增加执行超时时间
- 优化数据库查询
- 分批处理用户
- 考虑拆分为多个任务
3. 重复发放
症状: 用户多次收到积分
预防措施:
- 系统使用
referenceId
自动防止重复 - 检查数据库中
grantPeriod
的唯一性 - 确保每个端点只配置了一个定时任务
4. 未发放积分
检查:
// 验证订阅配置
console.log(appConfig.credits.subscription);
// 检查活动订阅
const purchases = await db
.select()
.from(purchase)
.where(eq(purchase.status, 'active'));
console.log(`Active subscriptions: ${purchases.length}`);
手动测试
手动测试端点:
# 测试发放端点
curl -X GET "https://yourdomain.com/api/jobs/credits/grant" \
-H "Authorization: Bearer your-cron-secret"
# 测试过期端点
curl -X GET "https://yourdomain.com/api/jobs/credits/expire" \
-H "Authorization: Bearer your-cron-secret"
📊 最佳实践
1. 时间安排
推荐计划:
- 发放: 01:00 UTC - 一天开始时确保积分早期可用
- 过期: 04:00 UTC - 发放后,防止竞态条件
为何分开时间?
- 防止数据库更新冲突
- 先发放,再过期清理
- 出现问题时更易调试
2. 监控
为以下情况设置警报:
- ✅ 任务执行失败
- ✅ 响应时间 > 5 秒
- ✅ 错误率 > 1%
- ✅ 24 小时内无成功执行