github.com/anth0d/nomad@v0.0.0-20221214183521-ae3a0a2cad06/ui/app/utils/classes/abstract-stats-tracker.js (about) 1 import Ember from 'ember'; 2 import Mixin from '@ember/object/mixin'; 3 import { assert } from '@ember/debug'; 4 import { task, timeout } from 'ember-concurrency'; 5 import jsonWithDefault from 'nomad-ui/utils/json-with-default'; 6 7 // eslint-disable-next-line ember/no-new-mixins 8 export default Mixin.create({ 9 url: '', 10 11 // The max number of data points tracked. Once the max is reached, 12 // data points at the head of the list are removed in favor of new 13 // data appended at the tail 14 bufferSize: 500, 15 16 // The number of consecutive request failures that can occur before an 17 // empty frame is appended 18 maxFrameMisses: 5, 19 20 fetch() { 21 assert( 22 'StatsTrackers need a fetch method, which should have an interface like window.fetch' 23 ); 24 }, 25 26 append(/* frame */) { 27 assert( 28 'StatsTrackers need an append method, which takes the JSON response from a request to url as an argument' 29 ); 30 }, 31 32 pause() { 33 assert( 34 'StatsTrackers need a pause method, which takes no arguments but adds a frame of data at the current timestamp with null as the value' 35 ); 36 }, 37 38 frameMisses: 0, 39 40 handleResponse(frame) { 41 if (frame.error) { 42 this.incrementProperty('frameMisses'); 43 if (this.frameMisses >= this.maxFrameMisses) { 44 // Missing enough data consecutively is effectively a pause 45 this.pause(); 46 this.set('frameMisses', 0); 47 } 48 return; 49 } else { 50 this.set('frameMisses', 0); 51 52 // Only append non-error frames 53 this.append(frame); 54 } 55 }, 56 57 // Uses EC as a form of debounce to prevent multiple 58 // references to the same tracker from flooding the tracker, 59 // but also avoiding the issue where different places where the 60 // same tracker is used needs to coordinate. 61 poll: task(function* () { 62 // Interrupt any pause attempt 63 this.signalPause.cancelAll(); 64 65 try { 66 const url = this.url; 67 assert('Url must be defined', url); 68 69 yield this.fetch(url) 70 .then(jsonWithDefault({ error: true })) 71 .then((frame) => this.handleResponse(frame)); 72 } catch (error) { 73 throw new Error(error); 74 } 75 76 yield timeout(Ember.testing ? 0 : 2000); 77 }).drop(), 78 79 signalPause: task(function* () { 80 // wait 2 seconds 81 yield timeout(Ember.testing ? 0 : 2000); 82 // if no poll called in 2 seconds, pause 83 this.pause(); 84 }).drop(), 85 });