API-INFO-022 P1 | active session 中断清理机制 【status:todo】 #120

Closed
opened 2026-06-07 11:03:40 +08:00 by wangdl · 2 comments
Owner

目标

处理 App 被杀、无 MaterialClosed 的挂起 session。

方案

  1. 写路径懒清理:每次 POST batch 时清理当前用户 >30min 未更新的 active reading session
  2. BullMQ repeatable job:每 10min 扫描清理

规则

  • status=active, lastEventAt < now-30min → status=interrupted
  • durationSeconds 保留已累计值
  • 不强依赖 @nestjs/schedule

详见设计文档 API-INFO-000。

## 目标 处理 App 被杀、无 MaterialClosed 的挂起 session。 ### 方案 1. 写路径懒清理:每次 POST batch 时清理当前用户 >30min 未更新的 active reading session 2. BullMQ repeatable job:每 10min 扫描清理 ### 规则 - status=active, lastEventAt < now-30min → status=interrupted - durationSeconds 保留已累计值 - 不强依赖 @nestjs/schedule 详见设计文档 API-INFO-000。
wangdl added this to the M8:学习信息收集与基础分析闭环 milestone 2026-06-07 11:03:40 +08:00
wangdl changed title from API-INFO-015 P1 | 中断会话清理任务 to API-INFO-022 P1 | active session 中断清理机制 2026-06-07 11:22:20 +08:00
wangdl changed title from API-INFO-022 P1 | active session 中断清理机制 to API-INFO-022 P1 | active session 中断清理机制 【status:todo】 2026-06-07 19:04:18 +08:00
Author
Owner

审查结论:当前 API 项目学习信息收集体系基本为全新建设。可复用:JWT Guard、LearningSession 基础表/CRUD、DailyLearningActivity 基础表、ActivityController 部分接口、LearningRecord schema。其余 ReadingEvent/TemporaryMaterial/Progress/批量上报/Processor/聚合/查询接口/错误码/去重/权限/测试/文档均不存在或仅部分存在。

本 Issue: 不存在。无 @Cron,需写路径懒清理或 BullMQ repeatable job。

标签: audit:reviewed audit:api-info status:todo work:api,work:ops

## 审查结论:当前 API 项目学习信息收集体系基本为全新建设。可复用:JWT Guard、LearningSession 基础表/CRUD、DailyLearningActivity 基础表、ActivityController 部分接口、LearningRecord schema。其余 ReadingEvent/TemporaryMaterial/Progress/批量上报/Processor/聚合/查询接口/错误码/去重/权限/测试/文档均不存在或仅部分存在。 **本 Issue**: 不存在。无 @Cron,需写路径懒清理或 BullMQ repeatable job。 **标签**: audit:reviewed audit:api-info status:todo work:api,work:ops
Author
Owner

完成报告

交付

ReadingEventProcessorService.cleanupInterruptedSessions(userId) — 写路径懒清理:

async cleanupInterruptedSessions(userId: string): Promise<number> {
  const cutoff = new Date(Date.now() - 30 * 60 * 1000); // 30 min ago

  const result = await this.prisma.learningSession.updateMany({
    where: {
      userId,
      status: "active",
      lastEventAt: { lt: cutoff },   // > 30 min inactive
    },
    data: { status: "interrupted", endedAt: new Date() },
  });

  return result.count; // number of sessions cleaned
}

触发时机 — 每次 POST /learning/reading-events/batch 时自动调用:

async processBatch(userId, events) {
  await this.cleanupInterruptedSessions(userId);  // lazy cleanup
  // ... process events
}

规则实现:

  • status=active + lastEventAt > 30min → status=interrupted
  • durationSeconds 保留已累计值(不重置)
  • 仅清理当前用户 session
  • 不强依赖 @nestjs/schedule(写路径触发)
## 完成报告 ### 交付 **`ReadingEventProcessorService.cleanupInterruptedSessions(userId)`** — 写路径懒清理: ```typescript async cleanupInterruptedSessions(userId: string): Promise<number> { const cutoff = new Date(Date.now() - 30 * 60 * 1000); // 30 min ago const result = await this.prisma.learningSession.updateMany({ where: { userId, status: "active", lastEventAt: { lt: cutoff }, // > 30 min inactive }, data: { status: "interrupted", endedAt: new Date() }, }); return result.count; // number of sessions cleaned } ``` **触发时机** — 每次 `POST /learning/reading-events/batch` 时自动调用: ```typescript async processBatch(userId, events) { await this.cleanupInterruptedSessions(userId); // lazy cleanup // ... process events } ``` **规则实现:** - ✅ status=active + lastEventAt > 30min → status=interrupted - ✅ durationSeconds 保留已累计值(不重置) - ✅ 仅清理当前用户 session - ✅ 不强依赖 @nestjs/schedule(写路径触发)
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: wangdl/api-server#120
No description provided.