UNPKG

4.39 kBJavaScriptView Raw
1/**
2 * @copyright Copyright (c) 2019 Maxim Khorin <maksimovichu@gmail.com>
3 */
4'use strict';
5
6const Base = require('../base/Component');
7
8module.exports = class Scheduler extends Base {
9
10 static getConstants () {
11 return {
12 EVENT_TASK_BEFORE_RUN: 'taskBeforeRun',
13 EVENT_TASK_DONE: 'taskDone',
14 EVENT_TASK_FAIL: 'taskFail'
15 };
16 }
17
18 constructor (config) {
19 super({
20 tasks: {},
21 refreshInterval: 60, // seconds
22 Task: require('./Task'),
23 ...config
24 });
25 this._taskMap = new DataMap;
26 this._taskBeforeRunHandler = this.taskBeforeRun.bind(this);
27 this._taskDoneHandler = this.taskDone.bind(this);
28 this._taskFailHandler = this.taskFail.bind(this);
29 this.Task = ClassHelper.normalizeSpawn(this.Task);
30 }
31
32 init () {
33 this.addTasks(this.tasks);
34 this.module.app.on(this.module.app.EVENT_AFTER_START, this.refresh.bind(this));
35 }
36
37 isActive () {
38 return !!this._timer;
39 }
40
41 start () {
42 this.stop();
43 this._timer = setTimeout(this.refresh.bind(this), this.refreshInterval * 1000);
44 }
45
46 stop () {
47 if (this._timer) {
48 clearTimeout(this._timer);
49 this._timer = null;
50 }
51 }
52
53 async refresh () {
54 for (const task of this._taskMap) {
55 await task.refresh();
56 }
57 this.start();
58 }
59
60 // TASKS
61
62 getTask (name) {
63 return this._taskMap.get(name);
64 }
65
66 addTasks (data, params) {
67 if (data) {
68 for (const name of Object.keys(data)) {
69 this.addTask(name, data[name], params);
70 }
71 }
72 }
73
74 addTask (name, config, params) {
75 if (this.getTask(name)) {
76 return this.log('error', `Task already exists: ${name}`);
77 }
78 try {
79 const task = this.createTask(name, config, params);
80 task.init();
81 this._taskMap.set(name, task);
82 this.log('info', `Task added: ${name}`);
83 } catch (err) {
84 this.log('error', `Invalid task: ${name}`, err);
85 }
86 }
87
88 createTask (name, config, params) {
89 config = {...this.Task, ...config};
90 const task = this.spawn(config, {...params, name, scheduler: this});
91 task.on(task.EVENT_BEFORE_RUN, this._taskBeforeRunHandler);
92 task.on(task.EVENT_DONE, this._taskDoneHandler);
93 task.on(task.EVENT_FAIL, this._taskFailHandler);
94 return task;
95 }
96
97 deleteTask (name) {
98 const task = this.getTask(name);
99 if (!task) {
100 return this.log('error', `Task not found: ${name}`);
101 }
102 if (this.detachTask(task)) {
103 this._taskMap.unset(name);
104 this.log('info', `Task deleted: ${name}`);
105 return true;
106 }
107 }
108
109 deleteAllTasks () {
110 for (const task of this._taskMap) {
111 this.detachTask(task);
112 }
113 this._taskMap.clear();
114 }
115
116 detachTask (task) {
117 try {
118 task.off();
119 task.stop();
120 return true;
121 } catch (err) {
122 this.log('error', `Task detaching failed: ${task.name}`, err);
123 }
124 }
125
126 async executeTasks (names) {
127 if (Array.isArray(names)) {
128 for (const name of names) {
129 await this.executeTask(name);
130 }
131 }
132 }
133
134 executeTask (name) {
135 const task = this.getTask(name);
136 if (!task) {
137 return this.log('error', `Task not found: ${name}`);
138 }
139 return task.isActive() ? task.execute() : null;
140 }
141
142 taskBeforeRun (event) {
143 return this.trigger(this.EVENT_TASK_BEFORE_RUN, event);
144 }
145
146 taskDone (event) {
147 this.log('info', `Task done: ${event.sender.name}`, event.result);
148 return this.trigger(this.EVENT_TASK_DONE, event);
149 }
150
151 taskFail (event) {
152 this.log('error', `Task failed: ${event.sender.name}:`, event.error);
153 return this.trigger(this.EVENT_TASK_FAIL, event);
154 }
155};
156module.exports.init();
157
158const ClassHelper = require('../helper/ClassHelper');
159const DataMap = require('../base/DataMap');
\No newline at end of file