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