diff options
author | Chocobozzz <florian.bigard@gmail.com> | 2017-02-27 21:56:55 +0100 |
---|---|---|
committer | Chocobozzz <florian.bigard@gmail.com> | 2017-02-27 21:56:55 +0100 |
commit | 99fdec464802e5d720fe08ead06b63368b115baf (patch) | |
tree | d3129ec4e37894036fc8e83ee17a953873f41e12 | |
parent | 05a9feaa48cea560abd9561434a3479ab1021643 (diff) | |
download | PeerTube-99fdec464802e5d720fe08ead06b63368b115baf.tar.gz PeerTube-99fdec464802e5d720fe08ead06b63368b115baf.tar.zst PeerTube-99fdec464802e5d720fe08ead06b63368b115baf.zip |
Fix request schedulers stats
8 files changed, 146 insertions, 60 deletions
diff --git a/client/src/app/+admin/requests/request-stats/request-stats.component.html b/client/src/app/+admin/requests/request-stats/request-stats.component.html index 9dbed1739..ca531258c 100644 --- a/client/src/app/+admin/requests/request-stats/request-stats.component.html +++ b/client/src/app/+admin/requests/request-stats/request-stats.component.html | |||
@@ -1,33 +1,37 @@ | |||
1 | <h3>Requests stats</h3> | 1 | <h3>Requests stats</h3> |
2 | 2 | ||
3 | <div *ngIf="stats !== null"> | 3 | <div *ngFor="let requestSchedulerName of statsTitles | keys"> |
4 | <div class="requests-general"> | 4 | <div class="block" *ngIf="stats[requestSchedulerName] !== null"> |
5 | <div> | 5 | <h4>{{ statsTitles[requestSchedulerName] }}</h4> |
6 | <span class="label-description">Remaining requests:</span> | ||
7 | {{ stats.totalRequests }} | ||
8 | </div> | ||
9 | 6 | ||
10 | <div> | 7 | <div class="requests-general"> |
11 | <span class="label-description">Interval seconds between requests:</span> | 8 | <div> |
12 | {{ stats.secondsInterval }} | 9 | <span class="label-description">Remaining requests:</span> |
13 | </div> | 10 | {{ stats[requestSchedulerName].totalRequests }} |
11 | </div> | ||
14 | 12 | ||
15 | <div> | 13 | <div> |
16 | <span class="label-description">Remaining time before the scheduled request:</span> | 14 | <span class="label-description">Interval seconds between requests:</span> |
17 | {{ stats.remainingSeconds }} | 15 | {{ stats[requestSchedulerName].secondsInterval }} |
18 | </div> | 16 | </div> |
19 | </div> | ||
20 | 17 | ||
21 | <div class="requests-limit"> | 18 | <div> |
22 | <div> | 19 | <span class="label-description">Remaining time before the scheduled request:</span> |
23 | <span class="label-description">Maximum number of different pods for a scheduled request:</span> | 20 | {{ stats[requestSchedulerName].remainingSeconds }} |
24 | {{ stats.requestsLimitPods }} | 21 | </div> |
25 | </div> | 22 | </div> |
26 | 23 | ||
27 | <div> | 24 | <div class="requests-limit"> |
28 | <span class="label-description">Maximum number of requests per pod for a scheduled request:</span> | 25 | <div> |
29 | {{ stats.requestsLimitPerPod }} | 26 | <span class="label-description">Maximum number of different pods for a scheduled request:</span> |
27 | {{ stats[requestSchedulerName].requestsLimitPods }} | ||
28 | </div> | ||
29 | |||
30 | <div> | ||
31 | <span class="label-description">Maximum number of requests per pod for a scheduled request:</span> | ||
32 | {{ stats[requestSchedulerName].requestsLimitPerPod }} | ||
33 | </div> | ||
30 | </div> | 34 | </div> |
31 | </div> | ||
32 | 35 | ||
36 | </div> | ||
33 | </div> | 37 | </div> |
diff --git a/client/src/app/+admin/requests/request-stats/request-stats.component.scss b/client/src/app/+admin/requests/request-stats/request-stats.component.scss index 9c68fba99..c9f724604 100644 --- a/client/src/app/+admin/requests/request-stats/request-stats.component.scss +++ b/client/src/app/+admin/requests/request-stats/request-stats.component.scss | |||
@@ -1,3 +1,7 @@ | |||
1 | .block { | ||
2 | margin-bottom: 40px; | ||
3 | } | ||
4 | |||
1 | .label-description { | 5 | .label-description { |
2 | display: inline-block; | 6 | display: inline-block; |
3 | font-weight: bold; | 7 | font-weight: bold; |
diff --git a/client/src/app/+admin/requests/request-stats/request-stats.component.ts b/client/src/app/+admin/requests/request-stats/request-stats.component.ts index 18855a5f8..85dd7e492 100644 --- a/client/src/app/+admin/requests/request-stats/request-stats.component.ts +++ b/client/src/app/+admin/requests/request-stats/request-stats.component.ts | |||
@@ -10,10 +10,30 @@ import { RequestService, RequestStats } from '../shared'; | |||
10 | styleUrls: [ './request-stats.component.scss' ] | 10 | styleUrls: [ './request-stats.component.scss' ] |
11 | }) | 11 | }) |
12 | export class RequestStatsComponent implements OnInit, OnDestroy { | 12 | export class RequestStatsComponent implements OnInit, OnDestroy { |
13 | stats: RequestStats = null; | 13 | statsTitles = { |
14 | requestScheduler: 'Basic request scheduler', | ||
15 | requestVideoEventScheduler: 'Video events request scheduler', | ||
16 | requestVideoQaduScheduler: 'Quick and dirty video updates request scheduler' | ||
17 | }; | ||
18 | |||
19 | stats: { [ id: string ]: RequestStats } = { | ||
20 | requestScheduler: null, | ||
21 | requestVideoEventScheduler: null, | ||
22 | requestVideoQaduScheduler: null | ||
23 | }; | ||
24 | |||
25 | private intervals: { [ id: string ]: number } = { | ||
26 | requestScheduler: null, | ||
27 | requestVideoEventScheduler: null, | ||
28 | requestVideoQaduScheduler: null | ||
29 | }; | ||
30 | |||
31 | private timeouts: { [ id: string ]: number } = { | ||
32 | requestScheduler: null, | ||
33 | requestVideoEventScheduler: null, | ||
34 | requestVideoQaduScheduler: null | ||
35 | }; | ||
14 | 36 | ||
15 | private interval: number = null; | ||
16 | private timeout: number = null; | ||
17 | 37 | ||
18 | constructor( | 38 | constructor( |
19 | private notificationsService: NotificationsService, | 39 | private notificationsService: NotificationsService, |
@@ -22,17 +42,19 @@ export class RequestStatsComponent implements OnInit, OnDestroy { | |||
22 | 42 | ||
23 | ngOnInit() { | 43 | ngOnInit() { |
24 | this.getStats(); | 44 | this.getStats(); |
25 | this.runInterval(); | 45 | this.runIntervals(); |
26 | } | 46 | } |
27 | 47 | ||
28 | ngOnDestroy() { | 48 | ngOnDestroy() { |
29 | if (this.interval !== null) { | 49 | Object.keys(this.stats).forEach(requestSchedulerName => { |
30 | window.clearInterval(this.interval); | 50 | if (this.intervals[requestSchedulerName] !== null) { |
31 | } | 51 | window.clearInterval(this.intervals[requestSchedulerName]); |
52 | } | ||
32 | 53 | ||
33 | if (this.timeout !== null) { | 54 | if (this.timeouts[requestSchedulerName] !== null) { |
34 | window.clearTimeout(this.timeout); | 55 | window.clearTimeout(this.timeouts[requestSchedulerName]); |
35 | } | 56 | } |
57 | }); | ||
36 | } | 58 | } |
37 | 59 | ||
38 | getStats() { | 60 | getStats() { |
@@ -43,14 +65,18 @@ export class RequestStatsComponent implements OnInit, OnDestroy { | |||
43 | ); | 65 | ); |
44 | } | 66 | } |
45 | 67 | ||
46 | private runInterval() { | 68 | private runIntervals() { |
47 | this.interval = window.setInterval(() => { | 69 | Object.keys(this.intervals).forEach(requestSchedulerName => { |
48 | this.stats.remainingMilliSeconds -= 1000; | 70 | this.intervals[requestSchedulerName] = window.setInterval(() => { |
71 | const stats = this.stats[requestSchedulerName]; | ||
49 | 72 | ||
50 | if (this.stats.remainingMilliSeconds <= 0) { | 73 | stats.remainingMilliSeconds -= 1000; |
51 | this.timeout = window.setTimeout(() => this.getStats(), this.stats.remainingMilliSeconds + 100); | 74 | |
52 | } | 75 | if (stats.remainingMilliSeconds <= 0) { |
53 | }, 1000); | 76 | this.timeouts[requestSchedulerName] = window.setTimeout(() => this.getStats(), stats.remainingMilliSeconds + 100); |
77 | } | ||
78 | }, 1000); | ||
79 | }); | ||
54 | } | 80 | } |
55 | 81 | ||
56 | 82 | ||
diff --git a/client/src/app/+admin/requests/shared/request.service.ts b/client/src/app/+admin/requests/shared/request.service.ts index 55b28bcfc..915d192a6 100644 --- a/client/src/app/+admin/requests/shared/request.service.ts +++ b/client/src/app/+admin/requests/shared/request.service.ts | |||
@@ -15,10 +15,20 @@ export class RequestService { | |||
15 | private restExtractor: RestExtractor | 15 | private restExtractor: RestExtractor |
16 | ) {} | 16 | ) {} |
17 | 17 | ||
18 | getStats(): Observable<RequestStats> { | 18 | getStats(): Observable<{ [ id: string ]: RequestStats }> { |
19 | return this.authHttp.get(RequestService.BASE_REQUEST_URL + 'stats') | 19 | return this.authHttp.get(RequestService.BASE_REQUEST_URL + 'stats') |
20 | .map(this.restExtractor.extractDataGet) | 20 | .map(this.restExtractor.extractDataGet) |
21 | .map((data) => new RequestStats(data)) | 21 | .map(this.buildRequestObjects) |
22 | .catch((res) => this.restExtractor.handleError(res)); | 22 | .catch((res) => this.restExtractor.handleError(res)); |
23 | } | 23 | } |
24 | |||
25 | private buildRequestObjects(data: any) { | ||
26 | const requestSchedulers = {}; | ||
27 | |||
28 | Object.keys(data).forEach(requestSchedulerName => { | ||
29 | requestSchedulers[requestSchedulerName] = new RequestStats(data[requestSchedulerName]); | ||
30 | }); | ||
31 | |||
32 | return requestSchedulers; | ||
33 | } | ||
24 | } | 34 | } |
diff --git a/client/src/app/shared/shared.module.ts b/client/src/app/shared/shared.module.ts index 99893c8b1..0f57ef078 100644 --- a/client/src/app/shared/shared.module.ts +++ b/client/src/app/shared/shared.module.ts | |||
@@ -5,6 +5,7 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms'; | |||
5 | import { RouterModule } from '@angular/router'; | 5 | import { RouterModule } from '@angular/router'; |
6 | 6 | ||
7 | import { BytesPipe } from 'angular-pipes/src/math/bytes.pipe'; | 7 | import { BytesPipe } from 'angular-pipes/src/math/bytes.pipe'; |
8 | import { KeysPipe } from 'angular-pipes/src/object/keys.pipe'; | ||
8 | import { DropdownModule } from 'ng2-bootstrap/dropdown'; | 9 | import { DropdownModule } from 'ng2-bootstrap/dropdown'; |
9 | import { ProgressbarModule } from 'ng2-bootstrap/progressbar'; | 10 | import { ProgressbarModule } from 'ng2-bootstrap/progressbar'; |
10 | import { PaginationModule } from 'ng2-bootstrap/pagination'; | 11 | import { PaginationModule } from 'ng2-bootstrap/pagination'; |
@@ -36,6 +37,7 @@ import { VideoAbuseService } from './video-abuse'; | |||
36 | 37 | ||
37 | declarations: [ | 38 | declarations: [ |
38 | BytesPipe, | 39 | BytesPipe, |
40 | KeysPipe, | ||
39 | SearchComponent | 41 | SearchComponent |
40 | ], | 42 | ], |
41 | 43 | ||
@@ -53,6 +55,7 @@ import { VideoAbuseService } from './video-abuse'; | |||
53 | ProgressbarModule, | 55 | ProgressbarModule, |
54 | Ng2SmartTableModule, | 56 | Ng2SmartTableModule, |
55 | BytesPipe, | 57 | BytesPipe, |
58 | KeysPipe, | ||
56 | 59 | ||
57 | SearchComponent | 60 | SearchComponent |
58 | ], | 61 | ], |
diff --git a/server/controllers/api/requests.js b/server/controllers/api/requests.js index 3e0d246d1..be352113e 100644 --- a/server/controllers/api/requests.js +++ b/server/controllers/api/requests.js | |||
@@ -1,9 +1,10 @@ | |||
1 | 'use strict' | 1 | 'use strict' |
2 | 2 | ||
3 | const express = require('express') | 3 | const express = require('express') |
4 | const parallel = require('async/parallel') | ||
4 | 5 | ||
5 | const constants = require('../../initializers/constants') | 6 | const constants = require('../../initializers/constants') |
6 | const db = require('../../initializers/database') | 7 | const friends = require('../../lib/friends') |
7 | const middlewares = require('../../middlewares') | 8 | const middlewares = require('../../middlewares') |
8 | const admin = middlewares.admin | 9 | const admin = middlewares.admin |
9 | const oAuth = middlewares.oauth | 10 | const oAuth = middlewares.oauth |
@@ -23,15 +24,33 @@ module.exports = router | |||
23 | // --------------------------------------------------------------------------- | 24 | // --------------------------------------------------------------------------- |
24 | 25 | ||
25 | function getStatsRequests (req, res, next) { | 26 | function getStatsRequests (req, res, next) { |
26 | db.Request.countTotalRequests(function (err, totalRequests) { | 27 | parallel({ |
28 | requestScheduler: buildRequestSchedulerFunction(friends.getRequestScheduler()), | ||
29 | requestVideoQaduScheduler: buildRequestSchedulerFunction(friends.getRequestVideoQaduScheduler()), | ||
30 | requestVideoEventScheduler: buildRequestSchedulerFunction(friends.getRequestVideoEventScheduler()) | ||
31 | }, function (err, result) { | ||
27 | if (err) return next(err) | 32 | if (err) return next(err) |
28 | 33 | ||
29 | return res.json({ | 34 | return res.json(result) |
30 | totalRequests: totalRequests, | ||
31 | requestsLimitPods: constants.REQUESTS_LIMIT_PODS, | ||
32 | requestsLimitPerPod: constants.REQUESTS_LIMIT_PER_POD, | ||
33 | remainingMilliSeconds: db.Request.remainingMilliSeconds(), | ||
34 | milliSecondsInterval: constants.REQUESTS_INTERVAL | ||
35 | }) | ||
36 | }) | 35 | }) |
37 | } | 36 | } |
37 | |||
38 | // --------------------------------------------------------------------------- | ||
39 | |||
40 | function buildRequestSchedulerFunction (requestScheduler) { | ||
41 | return function (callback) { | ||
42 | requestScheduler.remainingRequestsCount(function (err, count) { | ||
43 | if (err) return callback(err) | ||
44 | |||
45 | const result = { | ||
46 | totalRequests: count, | ||
47 | requestsLimitPods: requestScheduler.limitPods, | ||
48 | requestsLimitPerPod: requestScheduler.limitPerPod, | ||
49 | remainingMilliSeconds: requestScheduler.remainingMilliSeconds(), | ||
50 | milliSecondsInterval: requestScheduler.requestInterval | ||
51 | } | ||
52 | |||
53 | return callback(null, result) | ||
54 | }) | ||
55 | } | ||
56 | } | ||
diff --git a/server/lib/base-request-scheduler.js b/server/lib/base-request-scheduler.js index 309c1a261..1c6b78297 100644 --- a/server/lib/base-request-scheduler.js +++ b/server/lib/base-request-scheduler.js | |||
@@ -12,6 +12,7 @@ module.exports = class BaseRequestScheduler { | |||
12 | constructor (options) { | 12 | constructor (options) { |
13 | this.lastRequestTimestamp = 0 | 13 | this.lastRequestTimestamp = 0 |
14 | this.timer = null | 14 | this.timer = null |
15 | this.requestInterval = constants.REQUESTS_INTERVAL | ||
15 | } | 16 | } |
16 | 17 | ||
17 | activate () { | 18 | activate () { |
@@ -21,7 +22,7 @@ module.exports = class BaseRequestScheduler { | |||
21 | this.timer = setInterval(() => { | 22 | this.timer = setInterval(() => { |
22 | this.lastRequestTimestamp = Date.now() | 23 | this.lastRequestTimestamp = Date.now() |
23 | this.makeRequests() | 24 | this.makeRequests() |
24 | }, constants.REQUESTS_INTERVAL) | 25 | }, this.requestInterval) |
25 | } | 26 | } |
26 | 27 | ||
27 | deactivate () { | 28 | deactivate () { |
@@ -41,6 +42,10 @@ module.exports = class BaseRequestScheduler { | |||
41 | return constants.REQUESTS_INTERVAL - (Date.now() - this.lastRequestTimestamp) | 42 | return constants.REQUESTS_INTERVAL - (Date.now() - this.lastRequestTimestamp) |
42 | } | 43 | } |
43 | 44 | ||
45 | remainingRequestsCount (callback) { | ||
46 | return this.getRequestModel().countTotalRequests(callback) | ||
47 | } | ||
48 | |||
44 | // --------------------------------------------------------------------------- | 49 | // --------------------------------------------------------------------------- |
45 | 50 | ||
46 | // Make a requests to friends of a certain type | 51 | // Make a requests to friends of a certain type |
diff --git a/server/lib/friends.js b/server/lib/friends.js index 203f0e52c..7bd087d8c 100644 --- a/server/lib/friends.js +++ b/server/lib/friends.js | |||
@@ -19,8 +19,8 @@ const RequestVideoEventScheduler = require('./request-video-event-scheduler') | |||
19 | const ENDPOINT_ACTIONS = constants.REQUEST_ENDPOINT_ACTIONS[constants.REQUEST_ENDPOINTS.VIDEOS] | 19 | const ENDPOINT_ACTIONS = constants.REQUEST_ENDPOINT_ACTIONS[constants.REQUEST_ENDPOINTS.VIDEOS] |
20 | 20 | ||
21 | const requestScheduler = new RequestScheduler() | 21 | const requestScheduler = new RequestScheduler() |
22 | const requestSchedulerVideoQadu = new RequestVideoQaduScheduler() | 22 | const requestVideoQaduScheduler = new RequestVideoQaduScheduler() |
23 | const requestSchedulerVideoEvent = new RequestVideoEventScheduler() | 23 | const requestVideoEventScheduler = new RequestVideoEventScheduler() |
24 | 24 | ||
25 | const friends = { | 25 | const friends = { |
26 | activate, | 26 | activate, |
@@ -33,13 +33,16 @@ const friends = { | |||
33 | makeFriends, | 33 | makeFriends, |
34 | quitFriends, | 34 | quitFriends, |
35 | removeVideoToFriends, | 35 | removeVideoToFriends, |
36 | sendOwnedVideosToPod | 36 | sendOwnedVideosToPod, |
37 | getRequestScheduler, | ||
38 | getRequestVideoQaduScheduler, | ||
39 | getRequestVideoEventScheduler | ||
37 | } | 40 | } |
38 | 41 | ||
39 | function activate () { | 42 | function activate () { |
40 | requestScheduler.activate() | 43 | requestScheduler.activate() |
41 | requestSchedulerVideoQadu.activate() | 44 | requestVideoQaduScheduler.activate() |
42 | requestSchedulerVideoEvent.activate() | 45 | requestVideoEventScheduler.activate() |
43 | } | 46 | } |
44 | 47 | ||
45 | function addVideoToFriends (videoData, transaction, callback) { | 48 | function addVideoToFriends (videoData, transaction, callback) { |
@@ -142,7 +145,7 @@ function quitFriends (callback) { | |||
142 | }, | 145 | }, |
143 | 146 | ||
144 | function flushVideoQaduRequests (callbackAsync) { | 147 | function flushVideoQaduRequests (callbackAsync) { |
145 | requestSchedulerVideoQadu.flush(err => callbackAsync(err)) | 148 | requestVideoQaduScheduler.flush(err => callbackAsync(err)) |
146 | }, | 149 | }, |
147 | 150 | ||
148 | function getPodsList (callbackAsync) { | 151 | function getPodsList (callbackAsync) { |
@@ -215,6 +218,18 @@ function sendOwnedVideosToPod (podId) { | |||
215 | }) | 218 | }) |
216 | } | 219 | } |
217 | 220 | ||
221 | function getRequestScheduler () { | ||
222 | return requestScheduler | ||
223 | } | ||
224 | |||
225 | function getRequestVideoQaduScheduler () { | ||
226 | return requestVideoQaduScheduler | ||
227 | } | ||
228 | |||
229 | function getRequestVideoEventScheduler () { | ||
230 | return requestVideoEventScheduler | ||
231 | } | ||
232 | |||
218 | // --------------------------------------------------------------------------- | 233 | // --------------------------------------------------------------------------- |
219 | 234 | ||
220 | module.exports = friends | 235 | module.exports = friends |
@@ -345,13 +360,13 @@ function createRequest (options, callback) { | |||
345 | function createVideoQaduRequest (options, callback) { | 360 | function createVideoQaduRequest (options, callback) { |
346 | if (!callback) callback = utils.createEmptyCallback() | 361 | if (!callback) callback = utils.createEmptyCallback() |
347 | 362 | ||
348 | requestSchedulerVideoQadu.createRequest(options, callback) | 363 | requestVideoQaduScheduler.createRequest(options, callback) |
349 | } | 364 | } |
350 | 365 | ||
351 | function createVideoEventRequest (options, callback) { | 366 | function createVideoEventRequest (options, callback) { |
352 | if (!callback) callback = utils.createEmptyCallback() | 367 | if (!callback) callback = utils.createEmptyCallback() |
353 | 368 | ||
354 | requestSchedulerVideoEvent.createRequest(options, callback) | 369 | requestVideoEventScheduler.createRequest(options, callback) |
355 | } | 370 | } |
356 | 371 | ||
357 | function isMe (host) { | 372 | function isMe (host) { |