Skip to content

Latest commit

 

History

History
191 lines (130 loc) · 7.42 KB

底稿批量导出思路.md

File metadata and controls

191 lines (130 loc) · 7.42 KB

底稿批量导出

数据存储

  1. 每个任务存放到一个文件:由于任务的数据理论上没有上限,生产中有达到3000个的例子,且lowdb以json文件的形式存储, json文件会全量加载到内存中,所以每个人物存放到一个文件,每次只会加载一个任务
  2. 存储位置:由于任务是用户&身份区分的,所以存放到用户对应的文件夹下
  • user-userType:每个用户(身份)的存储文件夹
    • 'manuscriptBatchExport':固定字符串,这里是‘底稿批量导出’
      • queue: 任务列表
      • tasks-ExportID: 每个任务的队列详情

数据结构

有两个表

  • 任务列表:所有的导出任务
  • 任务详情:每个导出任务中,所有需导出文件的状态

任务列表的状态:

  • 初始化中:统计所有需下载的文件
  • 等待中:已初始化,但目前有其他任务执行中
  • 进行中:正在导出中
  • 已暂停:用户手动暂停,
  • 已完成:所有任务已处理,可成功可失败。
  • 已取消:用户手动取消,

任务详情:

  • 等待中:
  • 进行中:
  • 已暂停:
  • 已完成:成功 or 失败(包含失败原因)。

状态流转

taskManager如何实现线性操作

Q:如何关联2个表的状态,任务队列的状态,队列中文件的状态

A:不关联

队列的状态控制该任务是否初始化,进行中,暂停中,已取消,已完成等状态; 文件的状态反向控制任务状态,只有一种场景,就是所有文件都是已完成状态

任务列表/任务详情的状态变更,来源于:下载回调,用户操作。 同时操作两个表可能会导致状态不一致的bug。

  1. 单向状态流转:通过taskManager的操作,变更任务详情的状态,然后通过taskChangeCallback更新任务列表的状态。
  2. 任务列表特有的状态:
    1. 初始化中:任务详情正在统计中,不可操作
    2. 进行中:数据库中状态实际为等待中,对比taskManager的状态和缓存的id,显示为进行中
    3. 已取消:

TaskQueueManager 任务队列管理

基本流程:获取任务队列,取一个可执行任务,缓存当前的用户和任务,创建任务管理器并执行(每个任务管理器都会与当前用户,当前任务关联,避免切换用户导致的错误)。在完成的回调重复这个过程,直到所有任务完成,或因异常暂停。

需求:实现上,尽量简化,稳定第一

  1. 同一时间只有一个任务在运行
  2. 任务连续执行

场景:

  1. 登录后:基本流程
  2. 注销:基本流程,理论上任务都会401,任务都会暂停。现在在注销时清除主进程的user信息,中断这个不必要的重复流程
  3. 协议切换用户:基本流程,每次获取可执行的任务,都会重新获取当前用户信息,理论上不影响

细节说明: 3. 任务队列一旦失败,无论401,暂停,退出登录等,都置为暂停,不用多次重试

Q1: 如何实现任务的连续执行

每一个任务完成或其他原因终止,都重新拉取队列,避免:

  1. 401用户失效,此时user为空,所以拉取队列失败
  2. 用户变更,此时是完全不同的队列

注意:401需要清除当前用户的缓存信息,避免无效的执行

api实现

缓存正在运行的任务,数据包括:

  1. 当前任务
  2. 当前用户
  3. 创建的taskManager实例

TaskManager 任务管理器

职责内

  1. 维护队列:任务执行完成后,任务状态的流转,任务队列的变动
  2. 任务队列内的连续执行
  3. 队列

职责外

  1. 存储队列:任务队列变动时,队列的存储,存储的方式有多种选择,
  2. 多个任务队列连续执行:在onComplete中判断和处理

内部数据

  1. 队列
  2. 下载队列:等待下载的队列
  3. 下载中:正在下载的队列
  4. 暂停队列:任何情况停止的任务,可以包括:暂停,取消,失败等
  5. 完成队列:已完成的任务
  6. 队列的状态

如何终止任务

包含场景:队列执行完成,401,暂停或取消队列

  1. 内部任务循环执行,所有任务执行完成,任务终止
    • 方案:taskManager内部循环函数判断
  2. 401
    • 方案:taskManager内部循环函数判断,增加对这种场景的判断
  3. 用户操作,暂停,取消等
    • taskFun中提供一个用户存储abort的引用

以上场景,都需要taskFun内部返回特定表示终止的特定错误canceled_con的标识,

方案2:taskFun返回中添加一个是否继续执行下一个任务的标识,next === false时,停止队列,且taskChangeCallback不执行

方案1:taskFun:返回一个abort函数,赋值给taskManager内部的pause函数

数据库

参考选型

  • indexDB
  • levelDB
  • sqlite3

indexDB/Dexie.js:基于indexDB的封装,浏览器端的数据库,目前业务场景主要是在主进程端实现任务队列

levelDB:nosql数据库,基于levelDB,node和browser都可用,这里主要用于主进程

sqlite3:关系型数据库,主要是安装环境坑多

Q&A

Q: 创建任务 A:方案1:在创建任务时,获取所有文件信息,计算所有文件的路径。方案2:在创建任务时,仅记录项目,目录等主要信息,在导出时获取文件信息,计算路径。 方案2: 1.无法展示完整的导出列表,必须下载一部分展示一部分;2.下载中断后继续,定位困难 方案1:创建时计算,实现上逻辑更清晰,但在文件有修改的情况,文件的size会对不上,导致断点续传异常?是否考虑这种场景 方案3:使用方案1,但是下载时携带版本号,只下载创建任务时的版本

Q: 创建任务耗时随目录增加而增加,该过程放到主进程还是渲染进程?需要为上传下载队列生成专用的线程吗? A:上传下载主要是请求+I/O操作,都有异步版本,CPU占用并不繁重,没必要使用专用线程

Q:需要单例模式吗?

level ---- Node.js环境的数据库,基础api用法

按字典顺序排序的键值数据库,基于levelDB,用于Node.js的classical-level和browsers的browser-level的包装的入口

  • Node.js:基于levelDB
  • browser:基于indexDB 以下内容,只包含Node.js的部分

ref

https://github.com/Level/level

npm install level

API

db = new Level(location[, options])

创建一个新的数据库 or 打开一个已存在的数据库

  • location:本地路径(相对或绝对路径)
  • options:
    • keyEncoding (string or object, default 'utf8'): encoding to use for keys
    • valueEncoding (string or object, default 'utf8'): encoding to use for values.

db.status

获取当前数据的状态,只读,包括:opening open closing closed

db.open([callback])

打开数据库,成功或失败后调用callback or 返回promise,失败时参数为一个错误信息(nodejs的error-first模式)

一般来说,不用主动调用open,因为构造函数会自动调用,但也有使用场景

  1. 在主动close关闭数据库后,再次打开
  2. 用于捕获打开失败的错误信息?

db.close([callback])

关闭数据库,成功或失败后调用callback or 返回promise,失败时参数为一个错误信息(nodejs的error-first模式)

推荐:在使用完后关闭数据库,因为数据库可能有关联的资源,如文件句柄和锁。

db.get(key[, options][, callback])

获取key对应的value