]>
Commit | Line | Data |
---|---|---|
6fcd19ba C |
1 | import { isEmpty } from 'lodash' |
2 | import * as Promise 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 | |
4771e000 | 79 | protected 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 | |
6fcd19ba C |
89 | return makeSecureRequest(params) |
90 | .then(({ response, body }) => { | |
91 | if (response.statusCode !== 200 && response.statusCode !== 201 && response.statusCode !== 204) { | |
92 | throw new Error('Status code not 20x : ' + response.statusCode) | |
93 | } | |
94 | }) | |
95 | .catch(err => { | |
ad0997ad | 96 | logger.error('Error sending secure request to %s pod.', toPod.host, err) |
9e167724 | 97 | |
6fcd19ba C |
98 | throw err |
99 | }) | |
9e167724 C |
100 | } |
101 | ||
102 | // Make all the requests of the scheduler | |
65fcc311 | 103 | protected makeRequests () { |
6fcd19ba C |
104 | return this.getRequestModel().listWithLimitAndRandom(this.limitPods, this.limitPerPod) |
105 | .then((requestsGrouped: T) => { | |
106 | // We want to group requests by destinations pod and endpoint | |
4771e000 | 107 | const requestsToMake = this.buildRequestsObjects(requestsGrouped) |
6fcd19ba C |
108 | |
109 | // If there are no requests, abort | |
110 | if (isEmpty(requestsToMake) === true) { | |
111 | logger.info('No "%s" to make.', this.description) | |
112 | return { goodPods: [], badPods: [] } | |
113 | } | |
114 | ||
115 | logger.info('Making "%s" to friends.', this.description) | |
116 | ||
4771e000 C |
117 | const goodPods: number[] = [] |
118 | const badPods: number[] = [] | |
6fcd19ba C |
119 | |
120 | return Promise.map(Object.keys(requestsToMake), hashKey => { | |
121 | const requestToMake = requestsToMake[hashKey] | |
122 | const toPod: PodInstance = requestToMake.toPod | |
123 | ||
124 | return this.makeRequest(toPod, requestToMake.endpoint, requestToMake.datas) | |
125 | .then(() => { | |
126 | logger.debug('Removing requests for pod %s.', requestToMake.toPod.id, { requestsIds: requestToMake.ids }) | |
127 | goodPods.push(requestToMake.toPod.id) | |
128 | ||
129 | this.afterRequestHook() | |
130 | ||
131 | // Remove the pod id of these request ids | |
132 | return this.getRequestToPodModel().removeByRequestIdsAndPod(requestToMake.ids, requestToMake.toPod.id) | |
133 | }) | |
134 | .catch(err => { | |
135 | badPods.push(requestToMake.toPod.id) | |
ad0997ad | 136 | logger.info('Cannot make request to %s.', toPod.host, err) |
6fcd19ba C |
137 | }) |
138 | }, { concurrency: REQUESTS_IN_PARALLEL }).then(() => ({ goodPods, badPods })) | |
139 | }) | |
140 | .then(({ goodPods, badPods }) => { | |
141 | this.afterRequestsHook() | |
9e167724 | 142 | |
9e167724 | 143 | // All the requests were made, we update the pods score |
6fcd19ba | 144 | return db.Pod.updatePodsScore(goodPods, badPods) |
9e167724 | 145 | }) |
6fcd19ba | 146 | .catch(err => logger.error('Cannot get the list of "%s".', this.description, { error: err.stack })) |
9e167724 C |
147 | } |
148 | ||
65fcc311 | 149 | protected afterRequestHook () { |
9e167724 C |
150 | // Nothing to do, let children reimplement it |
151 | } | |
152 | ||
65fcc311 | 153 | protected afterRequestsHook () { |
9e167724 C |
154 | // Nothing to do, let children reimplement it |
155 | } | |
156 | } | |
65fcc311 C |
157 | |
158 | // --------------------------------------------------------------------------- | |
159 | ||
160 | export { | |
4771e000 C |
161 | AbstractRequestScheduler, |
162 | RequestsObjects | |
65fcc311 | 163 | } |