]>
Commit | Line | Data |
---|---|---|
6fcd19ba | 1 | import { isEmpty } from 'lodash' |
f5028693 | 2 | import * as Bluebird from 'bluebird' |
9e167724 | 3 | |
e02643f3 | 4 | import { database as db } from '../../initializers/database' |
65fcc311 | 5 | import { logger, makeSecureRequest } from '../../helpers' |
6fcd19ba | 6 | import { AbstractRequestClass, AbstractRequestToPodClass, PodInstance } from '../../models' |
65fcc311 C |
7 | import { |
8 | API_VERSION, | |
9 | REQUESTS_IN_PARALLEL, | |
10 | REQUESTS_INTERVAL | |
11 | } from '../../initializers' | |
12 | ||
4771e000 C |
13 | interface RequestsObjects<U> { |
14 | [ id: string ]: { | |
15 | toPod: PodInstance | |
16 | endpoint: string | |
17 | ids: number[] // ids | |
18 | datas: U[] | |
19 | } | |
20 | } | |
21 | ||
6fcd19ba | 22 | abstract class AbstractRequestScheduler <T> { |
69818c93 C |
23 | requestInterval: number |
24 | limitPods: number | |
25 | limitPerPod: number | |
26 | ||
65fcc311 C |
27 | protected lastRequestTimestamp: number |
28 | protected timer: NodeJS.Timer | |
65fcc311 C |
29 | protected description: string |
30 | ||
31 | constructor () { | |
9e167724 C |
32 | this.lastRequestTimestamp = 0 |
33 | this.timer = null | |
65fcc311 | 34 | this.requestInterval = REQUESTS_INTERVAL |
9e167724 C |
35 | } |
36 | ||
6fcd19ba C |
37 | abstract getRequestModel (): AbstractRequestClass<T> |
38 | abstract getRequestToPodModel (): AbstractRequestToPodClass | |
4771e000 | 39 | abstract buildRequestsObjects (requestsGrouped: T): RequestsObjects<any> |
65fcc311 | 40 | |
9e167724 C |
41 | activate () { |
42 | logger.info('Requests scheduler activated.') | |
43 | this.lastRequestTimestamp = Date.now() | |
44 | ||
45 | this.timer = setInterval(() => { | |
46 | this.lastRequestTimestamp = Date.now() | |
47 | this.makeRequests() | |
99fdec46 | 48 | }, this.requestInterval) |
9e167724 C |
49 | } |
50 | ||
51 | deactivate () { | |
52 | logger.info('Requests scheduler deactivated.') | |
53 | clearInterval(this.timer) | |
54 | this.timer = null | |
55 | } | |
56 | ||
57 | forceSend () { | |
58 | logger.info('Force requests scheduler sending.') | |
59 | this.makeRequests() | |
60 | } | |
61 | ||
62 | remainingMilliSeconds () { | |
63 | if (this.timer === null) return -1 | |
64 | ||
65fcc311 | 65 | return REQUESTS_INTERVAL - (Date.now() - this.lastRequestTimestamp) |
9e167724 C |
66 | } |
67 | ||
6fcd19ba C |
68 | remainingRequestsCount () { |
69 | return this.getRequestModel().countTotalRequests() | |
99fdec46 C |
70 | } |
71 | ||
6fcd19ba C |
72 | flush () { |
73 | return this.getRequestModel().removeAll() | |
65fcc311 C |
74 | } |
75 | ||
9e167724 C |
76 | // --------------------------------------------------------------------------- |
77 | ||
78 | // Make a requests to friends of a certain type | |
f5028693 | 79 | protected async makeRequest (toPod: PodInstance, requestEndpoint: string, requestsToMake: any) { |
9e167724 C |
80 | const params = { |
81 | toPod: toPod, | |
69818c93 | 82 | method: 'POST' as 'POST', |
65fcc311 | 83 | path: '/api/' + API_VERSION + '/remote/' + requestEndpoint, |
9e167724 C |
84 | data: requestsToMake // Requests we need to make |
85 | } | |
86 | ||
87 | // Make multiple retry requests to all of pods | |
88 | // The function fire some useful callbacks | |
f5028693 C |
89 | try { |
90 | const { response } = await makeSecureRequest(params) | |
91 | if (response.statusCode !== 200 && response.statusCode !== 201 && response.statusCode !== 204) { | |
92 | throw new Error('Status code not 20x : ' + response.statusCode) | |
93 | } | |
94 | } catch (err) { | |
95 | logger.error('Error sending secure request to %s pod.', toPod.host, err) | |
96 | ||
97 | throw err | |
98 | } | |
9e167724 C |
99 | } |
100 | ||
101 | // Make all the requests of the scheduler | |
f5028693 C |
102 | protected async makeRequests () { |
103 | let requestsGrouped: T | |
104 | ||
105 | try { | |
106 | requestsGrouped = await this.getRequestModel().listWithLimitAndRandom(this.limitPods, this.limitPerPod) | |
107 | } catch (err) { | |
108 | logger.error('Cannot get the list of "%s".', this.description, { error: err.stack }) | |
109 | throw err | |
110 | } | |
111 | ||
112 | // We want to group requests by destinations pod and endpoint | |
113 | const requestsToMake = this.buildRequestsObjects(requestsGrouped) | |
114 | ||
115 | // If there are no requests, abort | |
116 | if (isEmpty(requestsToMake) === true) { | |
117 | logger.info('No "%s" to make.', this.description) | |
118 | return { goodPods: [], badPods: [] } | |
119 | } | |
120 | ||
121 | logger.info('Making "%s" to friends.', this.description) | |
122 | ||
123 | const goodPods: number[] = [] | |
124 | const badPods: number[] = [] | |
125 | ||
126 | await Bluebird.map(Object.keys(requestsToMake), async hashKey => { | |
127 | const requestToMake = requestsToMake[hashKey] | |
128 | const toPod: PodInstance = requestToMake.toPod | |
129 | ||
130 | try { | |
131 | await this.makeRequest(toPod, requestToMake.endpoint, requestToMake.datas) | |
132 | logger.debug('Removing requests for pod %s.', requestToMake.toPod.id, { requestsIds: requestToMake.ids }) | |
133 | goodPods.push(requestToMake.toPod.id) | |
134 | ||
135 | this.afterRequestHook() | |
136 | ||
137 | // Remove the pod id of these request ids | |
138 | await this.getRequestToPodModel() | |
139 | .removeByRequestIdsAndPod(requestToMake.ids, requestToMake.toPod.id) | |
140 | } catch (err) { | |
141 | badPods.push(requestToMake.toPod.id) | |
142 | logger.info('Cannot make request to %s.', toPod.host, err) | |
143 | } | |
144 | }, { concurrency: REQUESTS_IN_PARALLEL }) | |
145 | ||
146 | this.afterRequestsHook() | |
147 | ||
148 | // All the requests were made, we update the pods score | |
d412e80e | 149 | db.Pod.updatePodsScore(goodPods, badPods) |
9e167724 C |
150 | } |
151 | ||
65fcc311 | 152 | protected afterRequestHook () { |
f5028693 | 153 | // Nothing to do, let children re-implement it |
9e167724 C |
154 | } |
155 | ||
65fcc311 | 156 | protected afterRequestsHook () { |
f5028693 | 157 | // Nothing to do, let children re-implement it |
9e167724 C |
158 | } |
159 | } | |
65fcc311 C |
160 | |
161 | // --------------------------------------------------------------------------- | |
162 | ||
163 | export { | |
4771e000 C |
164 | AbstractRequestScheduler, |
165 | RequestsObjects | |
65fcc311 | 166 | } |