OctoReport
OctoReport
HomeConsole文档
产品概述快速上手

内容采集

内容库与报告

知识库管理报告生成

投递与对话

触发收件箱(邮件通道)Ask 智能问答

运营

积分与日志
原子计费机制URL 去重技术系统可靠性
配置技巧优化与排查
OctoReport 常见问题与支持
亮点原子计费机制

原子计费机制

基于数据库事务的原子计费:积分扣费与任务执行强一致,失败自动回滚,绝不重复扣费。

基于数据库事务的原子计费机制,确保积分扣费与任务执行的一致性,绝不丢失积分、绝不重复扣费。

💡 核心承诺:任务失败自动退款,扣费与执行保证原子性,完整的交易审计日志。

1. 什么是原子计费

1.1 原子性(Atomicity)概念

原子性是数据库 ACID 特性之一,指一组操作要么全部成功,要么全部失败,不存在中间状态。

应用到计费场景:

  • ✅ 扣费成功 + 任务执行成功 → 用户付费,获得服务
  • ✅ 扣费失败 → 任务不执行
  • ✅ 任务执行失败 → 自动退款(回滚扣费)
  • ❌ 绝不允许:扣费成功但任务未执行(用户损失)
  • ❌ 绝不允许:任务执行成功但未扣费(系统损失)

1.2 为什么需要原子计费

问题场景 1:网络故障

传统方案:
1. 扣除 100 积分 → 成功
2. 调用 LLM API → 网络超时,失败
3. 结果:用户损失 100 积分,但没有获得服务

原子计费方案:
1. 开启事务
2. 扣除 100 积分(暂未提交)
3. 调用 LLM API → 失败
4. 事务回滚,积分退回
5. 结果:用户积分无损失 ✅

问题场景 2:系统崩溃

传统方案:
1. 扣除 100 积分 → 成功
2. 开始生成报告 → 服务器崩溃
3. 结果:用户损失 100 积分,报告未生成

原子计费方案:
1. 开启事务
2. 扣除 100 积分(暂未提交)
3. 开始生成报告 → 服务器崩溃
4. 事务自动回滚(数据库保证)
5. 结果:用户积分无损失 ✅

问题场景 3:重复扣费

传统方案:
1. 用户点击"生成报告"
2. 扣除 100 积分
3. 网络延迟,前端超时
4. 用户再次点击
5. 再次扣除 100 积分
6. 结果:重复扣费 200 积分 ❌

原子计费方案:
1. 检查是否有进行中的任务
2. 如果有 → 拒绝重复提交
3. 如果没有 → 开启事务
4. 扣费 + 创建任务记录(原子操作)
5. 结果:避免重复扣费 ✅

2. 原子计费的技术实现

2.1 数据库事务机制

技术栈:PostgreSQL + Prisma ORM

事务示例:

// 伪代码示例
async function generateReportWithBilling(userId, templateId) {
  // 1. 开启数据库事务
  return await prisma.$transaction(async (tx) => {
    // 2. 检查积分余额
    const user = await tx.user.findUnique({ where: { id: userId } })
    if (user.credits < estimatedCost) {
      throw new Error('Insufficient credits')
    }

    // 3. 扣除积分(暂未提交)
    await tx.user.update({
      where: { id: userId },
      data: { credits: user.credits - estimatedCost }
    })

    // 4. 创建积分交易记录(暂未提交)
    await tx.creditTransaction.create({
      data: {
        userId,
        amount: -estimatedCost,
        type: 'REPORT_GENERATION',
        status: 'PENDING'
      }
    })

    // 5. 创建报告任务(暂未提交)
    const report = await tx.report.create({
      data: { userId, templateId, status: 'PENDING' }
    })

    // 6. 事务提交(所有操作一起成功或失败)
    return report
  })

  // 7. 异步执行报告生成
  //    如果失败,通过 Worker 回调退款
}

关键点:

  • ✅ 所有操作在同一事务中(扣费、创建记录、更新状态)
  • ✅ 任何一步失败,整个事务回滚
  • ✅ 提交后才真正扣费(不可逆)

2.2 失败自动退款机制

退款流程:

  1. 任务执行失败(Worker 检测到异常)
  2. Worker 回调(通知系统任务失败)
  3. 查询扣费记录(根据任务 ID 查找对应的积分交易)
  4. 创建退款交易(新增一条 amount > 0 的交易记录)
  5. 更新用户积分(credits += refundAmount)
  6. 更新任务状态(status = FAILED)

退款示例:

// 伪代码
async function refundOnFailure(taskId, reason) {
  return await prisma.$transaction(async (tx) => {
    // 1. 查找任务和扣费记录
    const task = await tx.report.findUnique({ where: { id: taskId } })
    const transaction = await tx.creditTransaction.findFirst({
      where: {
        type: 'REPORT_GENERATION',
        reportId: taskId,
        amount: { lt: 0 } // 扣费记录
      }
    })

    // 2. 创建退款记录
    await tx.creditTransaction.create({
      data: {
        userId: task.userId,
        amount: Math.abs(transaction.amount), // 正数(退款)
        type: 'REFUND',
        description: `任务失败自动退款:${reason}`
      }
    })

    // 3. 更新用户积分
    await tx.user.update({
      where: { id: task.userId },
      data: {
        credits: { increment: Math.abs(transaction.amount) }
      }
    })

    // 4. 更新任务状态
    await tx.report.update({
      where: { id: taskId },
      data: { status: 'FAILED', error: reason }
    })
  })
}

2.3 重复提交防护

防护机制:

  • 幂等性检查:提交前检查是否有相同任务在执行中
  • 唯一约束:数据库层面防止重复插入
  • 状态机:任务状态只能单向流转(PENDING → PROCESSING → SUCCESS/FAILED)

检查示例:

// 伪代码
async function createTaskWithCheck(userId, templateId) {
  // 1. 检查是否有相同任务在执行
  const existingTask = await prisma.report.findFirst({
    where: {
      userId,
      templateId,
      status: { in: ['PENDING', 'PROCESSING'] }
    }
  })

  if (existingTask) {
    throw new Error('任务已在执行中,请勿重复提交')
  }

  // 2. 创建新任务(原子计费)
  return await createReportWithBilling(userId, templateId)
}

3. 与传统计费方案对比

特性传统计费原子计费
扣费与执行一致性❌ 不保证✅ 事务保证
任务失败退款❌ 手动申请✅ 自动退款
重复扣费风险⚠️ 存在风险✅ 幂等性检查
积分丢失风险⚠️ 系统故障时可能丢失✅ 事务回滚保护
审计追踪⚠️ 可能不完整✅ 完整交易记录
用户信任度⭐⭐⭐⭐⭐⭐⭐⭐

3.1 真实案例对比

案例 1:报告生成失败

步骤传统计费原子计费
1. 点击"生成报告"扣除 200 积分开启事务,暂扣 200 积分
2. 执行生成任务LLM API 失败LLM API 失败
3. 处理失败任务标记失败事务回滚 + 自动退款
4. 用户操作提交退款申请无需操作(已退款)
5. 最终结果3-7天后退款立即退款 ✅

案例 2:网络延迟重复提交

步骤传统计费原子计费
1. 首次点击扣除 200 积分扣除 200 积分
2. 网络延迟前端超时前端超时
3. 用户再次点击再次扣除 200 积分检测到任务进行中,拒绝
4. 最终结果重复扣费 400 积分 ❌只扣费 200 积分 ✅

4. 交易审计日志

4.1 完整的交易记录

记录内容:

  • id: 交易唯一ID
  • userId: 用户ID
  • amount: 金额(正数=充值/退款,负数=扣费)
  • type: 交易类型(REPORT_GENERATION, CONTENT_COLLECTION, CHAT, REFUND 等)
  • description: 交易描述
  • createdAt: 交易时间
  • metadata: 关联的任务ID、报告ID等

查询示例:

// 用户积分消费明细
积分管理 → 消费明细

示例记录:
┌─────────────────────┬────────┬──────────┬───────────────────────┐
│ 时间                │ 金额   │ 类型     │ 描述                  │
├─────────────────────┼────────┼──────────┼───────────────────────┤
│ 2025-10-27 10:00    │ -200   │ 报告生成 │ 每日新闻摘要          │
│ 2025-10-27 10:05    │ +200   │ 退款     │ 任务失败自动退款      │
│ 2025-10-27 11:00    │ -50    │ 数据收集 │ RSS订阅源执行         │
│ 2025-10-27 12:00    │ -20    │ 问答     │ 知识库问答            │
│ 2025-10-27 14:00    │ +10000 │ 兑换码   │ 充值码:ABC123        │
└─────────────────────┴────────┴──────────┴───────────────────────┘

4.2 审计追踪能力

支持的查询:

  • 按时间范围查询(如"最近 7 天")
  • 按交易类型筛选(如"只看报告生成")
  • 按金额筛选(如"只看扣费"或"只看退款")
  • 导出为 CSV(用于财务审计)

数据一致性保证:

  • ✅ 每笔扣费都有对应的任务记录
  • ✅ 失败任务必有退款记录
  • ✅ 积分余额 = 初始积分 + 所有交易金额之和

5. 用户保障措施

5.1 积分安全承诺

✅ 我们的承诺:

  • 任务失败,100% 自动退款,无需申请
  • 系统故障,积分绝不丢失(数据库事务保护)
  • 重复提交,自动拒绝,避免重复扣费
  • 所有交易,完整记录,随时可查

5.2 余额不足保护

检查机制:

  1. 提交前检查:前端显示预估成本,余额不足时禁用按钮
  2. 事务中检查:扣费前再次检查余额,不足时回滚事务
  3. 并发控制:使用数据库行级锁,避免超支

示例场景:

用户当前余额:100 积分

情况 1:单个任务
- 预估成本:80 积分
- 检查结果:余额充足 ✅
- 操作:允许提交

情况 2:并发任务
- 用户同时提交 2 个任务,每个 60 积分
- 事务 A:扣除 60 积分 → 余额 40 → 提交成功
- 事务 B:尝试扣除 60 积分 → 余额不足 → 回滚
- 结果:只有 1 个任务成功,避免超支 ✅

情况 3:实际成本超出预估
- 预估成本:100 积分
- 实际成本:120 积分(LLM token 超出预估)
- 处理:任务失败 + 退款 100 积分
- 提示:请充值后重试

5.3 争议解决机制

如果你发现异常扣费:

  1. 查看"消费明细"(积分管理 → 消费明细)
  2. 找到异常交易记录
  3. 查看关联的任务日志(点击交易记录查看详情)
  4. 如果确认异常,联系技术支持(提供交易ID)
  5. 技术支持会根据审计日志核实并处理

争议处理时效:

  • ✅ 系统自动退款:实时(任务失败后立即退款)
  • ✅ 人工审核退款:1-3 个工作日

6. 技术优势总结

技术特性实现方式用户收益
事务原子性PostgreSQL 事务 + Prisma ORM扣费与执行一致,绝不丢失积分
自动退款Worker 回调 + 事务处理任务失败立即退款,无需等待
重复提交防护幂等性检查 + 状态机避免重复扣费,保护资金安全
审计日志完整的交易记录表随时查询,争议可追溯
并发控制数据库行级锁避免超支,余额准确

7. 常见问题

Q1: 任务失败后,积分多久会退回?

A:立即退回。当 Worker 检测到任务失败时,会自动触发退款流程(通常在任务失败后 1-3 秒内完成)。你可以在"消费明细"中看到退款记录。

Q2: 如果我重复点击"生成报告",会重复扣费吗?

A:不会。系统会检测是否有相同任务在执行中,如果有,会拒绝重复提交并提示"任务已在执行中"。

Q3: 预估成本和实际成本不一致怎么办?

A:预估成本是基于历史数据计算的参考值。如果实际成本超出预估:

  • 余额不足 → 任务失败 + 退款预扣的积分
  • 余额充足 → 按实际成本扣费
  • 建议:保留一定余额缓冲(如预估成本的 1.5 倍)

Q4: 我可以查看所有的历史交易吗?

A:可以。进入"积分管理 → 消费明细",可以查看所有交易记录,支持:

  • 按时间范围筛选(如"最近 30 天")
  • 按交易类型筛选(如"只看退款")
  • 按金额筛选(如"只看大于 100 积分的交易")
  • 导出为 CSV(用于个人记账)

Q5: 原子计费是否会影响系统性能?

A:影响极小。事务开销通常在 1-5ms,对用户体验几乎无感知。我们的优化措施:

  • 使用数据库连接池(减少连接开销)
  • 异步执行耗时任务(报告生成、内容收集)
  • 合理的事务粒度(只锁必要的行)

下一步

  • 系统可靠性 - 了解故障转移和健康检查机制
  • URL去重技术 - 了解内容去重机制
  • 积分与日志 - 查看积分管理和消费明细

积分与日志

了解如何获取积分、查看消费明细、使用兑换码以及查看任务日志

URL 去重技术

智能 URL 去重机制:避免重复抓取、节省成本、保留内容版本历史。OctoReport 的核心技术优势之一。

On this page

1. 什么是原子计费1.1 原子性(Atomicity)概念1.2 为什么需要原子计费2. 原子计费的技术实现2.1 数据库事务机制2.2 失败自动退款机制2.3 重复提交防护3. 与传统计费方案对比3.1 真实案例对比4. 交易审计日志4.1 完整的交易记录4.2 审计追踪能力5. 用户保障措施5.1 积分安全承诺5.2 余额不足保护5.3 争议解决机制6. 技术优势总结7. 常见问题Q1: 任务失败后,积分多久会退回?Q2: 如果我重复点击"生成报告",会重复扣费吗?Q3: 预估成本和实际成本不一致怎么办?Q4: 我可以查看所有的历史交易吗?Q5: 原子计费是否会影响系统性能?下一步