离线学习与多端进度同步:在线心跳、Redis 缓冲与断点续考技术实现
员工可能在电脑上看了半节课,晚上通勤时想用手机接着看;考试进行到一半浏览器崩溃,重新进入时希望从中断处继续。表面上这是"多端一致"和"断点续学"的体验问题,底层却涉及进度采集、写入削峰、服务端聚合和考试状态恢复。
织码在线教育系统采用一条清晰的在线链路:客户端高频上报学习事实,进度先写入 Redis,再由 XXL-JOB 批量聚合落库;课程完成、证书触发和考试成绩始终由服务端裁决。
需要先明确边界:当前实现不是离线学习引擎,不包含本地缓存、断网队列和断网补传。所有进度同步与断点续考都建立在客户端能够在线访问服务端的前提上。

一、进度采集:上报学习事实,而不是直接提交完成
学习端观看课程或任务课时时,通过 AuthCourseSignReq、AuthTaskSignReq 向服务端上报,而不是等到课程结束才一次性提交。
java
public class AuthCourseSignReq {
private Long courseId;
private Long periodId;
private String clientIp;
private Boolean appWatch;
private String guid;
}
服务端记录落到 CourseUserStudy,任务场景对应 TaskUserStudy。常见事实字段包括:
| 字段 | 作用 |
|---|---|
courseId / chapterId / periodId |
定位课程、章节和课时 |
currentDuration |
视频或音频已观看时长 |
currentPage |
文档当前阅读页码 |
progress |
当前学习进度百分比 |
periodType / materialType |
区分素材、直播、考试等类型 |
这些字段是"用户已经学习到哪里"的事实记录。客户端可以上报,但不能通过上报一个 completed=true 绕过服务端的完成规则。
二、Redis 缓冲:把高频心跳转换为批量写入

如果每次心跳都直接更新 MySQL,学习人数和上报频率增加后会产生大量小事务。系统将高频进度先写入 Redis,再由 CourseUserStudyJob 定时扫描和批量落库:
java
@Component
public class CourseUserStudyJob {
@XxlJob("courseUserStudyHandler")
public void execute() {
// 1. 扫描 Redis 中的进度缓冲
// 2. 按用户 + 课时聚合最新有效值
// 3. 批量更新 course_user_study
// 4. 触发完成判定与证书逻辑
}
}
工程上要注意三个一致性问题:同一用户同一课时的进度需要聚合;旧请求不能覆盖新进度;批量任务失败后要能够安全重试。有效进度通常只允许向前推进,完成事件必须具备幂等语义。
三、服务端完成判定:客户端只提供事实
课程达到 certStudyProgress 等阈值后,完成判定在聚合任务或业务服务端执行。服务端需要结合课时类型、必修规则、学习时长和考试结果重新计算,而不是信任客户端传入的百分比。
java
public void recalculate(Long userId, Long courseId) {
StudySnapshot snapshot = studyRepo.loadSnapshot(userId, courseId);
if (snapshot.requiredDone() &&
snapshot.progress() >= snapshot.certStudyProgress()) {
courseCompletionService.markCompleted(userId, courseId);
}
}
完成状态一旦触发证书或任务后续流程,就需要记录事件来源和处理结果,避免定时任务重复执行时重复发放或重复通知。
四、断点续考:服务端时间不能被刷新重置

考试中断比普通视频续播更严格。AuthExamContinueResp 用于恢复考试记录,其中 userAnswer 回填已保存答案,surplusTime 由服务端根据考试开始时间、考试时长和当前时间计算。
java
public class AuthExamContinueResp {
private Long recordId;
private Integer surplusTime;
private List<UserAnswerVO> userAnswer;
}
关键点是不能使用客户端本地倒计时作为权威时间。考生刷新页面、切换设备或浏览器崩溃后,服务端仍按考试记录计算剩余时间,从而避免重复进入考试时重置时钟。已答内容来自 ExamUserAnswer,而不是依赖浏览器内存。
成绩口径由 examScoreType 决定:取最高分或取最新分。多次考试的成绩选择必须在服务端执行,前端只展示最终结果。
五、多端一致性:不同入口读取同一份服务端记录

客户端类型由 ClientTypeEnum 区分 PC、H5、MP、ANDROID 和 IOS。客户端类型可以用于统计学习行为和区分上报场景,但课程进度、任务进度、答案和成绩仍以服务端记录为准。
这意味着用户可以在 PC 上学习后用 App 继续,但前提是 App 能够在线读取服务端最新状态。当前实现不支持离线缓存、断网本地队列、断网补传,也不支持离线考试;弱网或断网时应提示网络异常,而不是承诺数据稍后自动同步。
六、工程可靠性:围绕在线链路补齐可观测性
生产环境建议记录进度上报成功率、Redis 缓冲数量、批量落库耗时、落库失败重试次数、完成判定延迟、断点续考恢复失败率和考试答案保存失败率。指标应按客户端类型、课程、网络状态和时间窗口拆分,便于定位是某端接口异常还是某类课程数据异常。
七、总结
织码在线教育系统的多端进度同步方案,可以概括为:客户端在线上报学习事实,Redis 暂存高频进度,XXL-JOB 批量聚合落库,服务端统一判定完成和成绩,考试恢复时按服务端时间计算剩余时长。
它解决的是在线条件下的多端一致和断点续考,不是离线学习系统。把"支持什么"和"不支持什么"讲清楚,才能让产品宣传、技术实施和用户预期保持一致。
如需私有化部署报价、远程产品演示,可访问官网 https://www.weavecodes.com/ ,私信作者领取企业落地案例。
。把"支持什么"和"不支持什么"讲清楚,才能让产品宣传、技术实施和用户预期保持一致。
如需私有化部署报价、远程产品演示,可访问官网 https://www.weavecodes.com/ ,私信作者领取企业落地案例。