1
0

task.ts 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. import BaseService from '../../base';
  2. import { CreateTaskDto, UpdateTaskDto } from '../../../dto/admin/sys/task';
  3. import SysTask from '../../../entities/admin/sys/task';
  4. /**
  5. * 任务调度服务
  6. */
  7. export default class SysTaskService extends BaseService {
  8. /**
  9. * 初始化任务,系统启动前调用
  10. */
  11. async initTask() {
  12. const jobs = await this.app.queue.sys.getJobs([ 'active', 'delayed', 'failed', 'paused', 'waiting', 'completed' ]);
  13. for (let i = 0; i < jobs.length; i++) {
  14. // 先移除所有已存在的任务
  15. await jobs[i].remove();
  16. }
  17. // 查找所有需要运行的任务
  18. const tasks = await this.getRepo().admin.sys.Task.find({ status: 1 });
  19. if (tasks && tasks.length > 0) {
  20. for (const t of tasks) {
  21. this.start(t);
  22. }
  23. }
  24. }
  25. /**
  26. * 分页查询
  27. */
  28. async page(page: number, count: number) {
  29. const result = await this.getRepo().admin.sys.Task.find({
  30. order: {
  31. id: 'ASC',
  32. },
  33. take: count,
  34. skip: page * count,
  35. });
  36. return result;
  37. }
  38. /**
  39. * count task
  40. */
  41. async count() {
  42. return await this.getRepo().admin.sys.Task.count();
  43. }
  44. /**
  45. * task info
  46. */
  47. async info(id: number) {
  48. return await this.getRepo().admin.sys.Task.findOne({ id });
  49. }
  50. /**
  51. * delete task
  52. */
  53. async delete(task: SysTask) {
  54. if (!task) {
  55. throw new Error('Task is Empty');
  56. }
  57. await this.stop(task);
  58. await this.getRepo().admin.sys.Task.delete(task.id);
  59. }
  60. /**
  61. * 添加任务
  62. */
  63. async addOrUpdate(param: CreateTaskDto | UpdateTaskDto) {
  64. const result = await this.getRepo().admin.sys.Task.save(param);
  65. const task = await this.info(result.id);
  66. if (result.status === 0) {
  67. await this.stop(task!);
  68. } else if (result.status === 1) {
  69. await this.start(task!);
  70. }
  71. }
  72. /**
  73. * 手动执行一次
  74. */
  75. async once(task: SysTask) {
  76. if (task) {
  77. await this.app.queue.sys.add({ id: task.id, service: task.service, args: task.data },
  78. { jobId: task.id, removeOnComplete: true, removeOnFail: true });
  79. } else {
  80. throw new Error('Task is Empty');
  81. }
  82. }
  83. /**
  84. * 启动任务
  85. */
  86. async start(task: SysTask) {
  87. if (!task) {
  88. throw new Error('Task is Empty');
  89. }
  90. // 先停掉之前存在的任务
  91. await this.stop(task);
  92. let repeat: any;
  93. if (task.type === 1) {
  94. // 间隔 Repeat every millis (cron setting cannot be used together with this setting.)
  95. repeat = {
  96. every: task.every,
  97. };
  98. } else {
  99. // cron
  100. repeat = {
  101. cron: task.cron,
  102. };
  103. // Start date when the repeat job should start repeating (only with cron).
  104. if (task.startTime) {
  105. repeat.startDate = task.startTime;
  106. }
  107. if (task.endTime) {
  108. repeat.endDate = task.endTime;
  109. }
  110. }
  111. if (task.limit > 0) {
  112. repeat.limit = task.limit;
  113. }
  114. const job = await this.app.queue.sys.add({ id: task.id, service: task.service, args: task.data },
  115. { jobId: task.id, removeOnComplete: true, removeOnFail: true, repeat });
  116. if (job && job.opts) {
  117. await this.getRepo().admin.sys.Task.update(task.id, { jobOpts: JSON.stringify(job.opts.repeat), status: 1 });
  118. } else {
  119. // update status to 0,标识暂停任务,因为启动失败
  120. job && await job.remove();
  121. await this.getRepo().admin.sys.Task.update(task.id, { status: 0 });
  122. throw new Error('Task Start failed');
  123. }
  124. }
  125. /**
  126. * 停止任务
  127. */
  128. async stop(task: SysTask) {
  129. if (!task) {
  130. throw new Error('Task is Empty');
  131. }
  132. const exist = await this.existJob(task.id.toString());
  133. if (!exist) {
  134. await this.getRepo().admin.sys.Task.update(task.id, { status: 0 });
  135. return;
  136. }
  137. const jobs = await this.app.queue.sys.getJobs([ 'active', 'delayed', 'failed', 'paused', 'waiting', 'completed' ]);
  138. for (let i = 0; i < jobs.length; i++) {
  139. if (jobs[i].data.id === task.id) {
  140. await jobs[i].remove();
  141. }
  142. }
  143. await this.getRepo().admin.sys.Task.update(task.id, { status: 0 });
  144. // if (task.jobOpts) {
  145. // await this.app.queue.sys.removeRepeatable(JSON.parse(task.jobOpts));
  146. // // update status
  147. // await this.getRepo().admin.sys.Task.update(task.id, { status: 0 });
  148. // }
  149. }
  150. /**
  151. * 查看队列中任务是否存在
  152. */
  153. async existJob(jobId: string) {
  154. const jobs = await this.app.queue.sys.getRepeatableJobs();
  155. const ids = jobs.map(e => {
  156. return e.id;
  157. });
  158. return ids.includes(jobId);
  159. }
  160. /**
  161. * 更新任务完成状态
  162. */
  163. async updateTaskCompleteStatus(tid: number) {
  164. const result = await this.app.queue.sys.getRepeatableJobs();
  165. const task = await this.getRepo().admin.sys.Task.findOne({ id: tid });
  166. const jobOpts = JSON.parse(task!.jobOpts);
  167. // 如果下次执行时间小于当前时间,则表示已经执行完成。
  168. for (const task of result) {
  169. const currentTime = new Date().getTime();
  170. if (task.id && task.id === tid.toString()
  171. && (jobOpts.cron ? task.cron === jobOpts.cron : task.every === jobOpts.every) && task.next < currentTime) {
  172. // 如果下次执行时间小于当前时间,则表示已经执行完成。
  173. await this.getRepo().admin.sys.Task.update(tid, { status: 2 });
  174. }
  175. }
  176. }
  177. /**
  178. * 根据serviceName调用service
  179. */
  180. async callService(serviceName: string, args: string) {
  181. if (serviceName) {
  182. let serviceTmp = this.service;
  183. const arr = serviceName.split('.');
  184. for (let i = 0; i < arr.length; i++) {
  185. if (i === arr.length - 1) {
  186. if (args) {
  187. await serviceTmp[arr[arr.length - 1]](JSON.parse(args));
  188. } else {
  189. await serviceTmp[arr[arr.length - 1]]();
  190. }
  191. } else {
  192. serviceTmp = serviceTmp[arr[i]];
  193. }
  194. }
  195. }
  196. }
  197. }