github.com/anth0d/nomad@v0.0.0-20221214183521-ae3a0a2cad06/ui/app/services/stats-trackers-registry.js (about) 1 import { computed } from '@ember/object'; 2 import Service, { inject as service } from '@ember/service'; 3 import { LRUMap } from 'lru_map'; 4 import NodeStatsTracker from 'nomad-ui/utils/classes/node-stats-tracker'; 5 import AllocationStatsTracker from 'nomad-ui/utils/classes/allocation-stats-tracker'; 6 7 // An unbounded number of stat trackers is a great way to gobble up all the memory 8 // on a machine. This max number is unscientific, but aims to balance losing 9 // stat trackers a user is likely to return to with preventing gc from freeing 10 // memory occupied by stat trackers a user is likely to no longer care about 11 const MAX_STAT_TRACKERS = 10; 12 let registry; 13 14 const exists = (tracker, prop) => 15 tracker.get(prop) && 16 !tracker.get(prop).isDestroyed && 17 !tracker.get(prop).isDestroying; 18 19 export default class StatsTrackersRegistryService extends Service { 20 @service token; 21 22 constructor() { 23 super(...arguments); 24 25 // The LRUMap limits the number of trackers tracked by making room for 26 // new entries beyond the limit by removing the least recently used entry. 27 registry = new LRUMap(MAX_STAT_TRACKERS); 28 } 29 30 // A read-only way of getting a reference to the registry. 31 // Since this could be overwritten by a bad actor, it isn't 32 // used in getTracker 33 @computed 34 get registryRef() { 35 return registry; 36 } 37 38 getTracker(resource) { 39 if (!resource) return; 40 41 const type = resource && resource.constructor.modelName; 42 const key = `${type}:${resource.get('id')}`; 43 const Constructor = 44 type === 'node' ? NodeStatsTracker : AllocationStatsTracker; 45 const resourceProp = type === 'node' ? 'node' : 'allocation'; 46 47 const cachedTracker = registry.get(key); 48 if (cachedTracker) { 49 // It's possible for the resource on a cachedTracker to have been 50 // deleted. Rebind it if that's the case. 51 if (!exists(cachedTracker, resourceProp)) 52 cachedTracker.set(resourceProp, resource); 53 return cachedTracker; 54 } 55 56 const tracker = Constructor.create({ 57 fetch: (url) => this.token.authorizedRequest(url), 58 [resourceProp]: resource, 59 }); 60 61 registry.set(key, tracker); 62 63 return tracker; 64 } 65 }