github.com/emate/nomad@v0.8.2-wo-binpacking/ui/app/components/allocation-row.js (about) 1 import Ember from 'ember'; 2 import { inject as service } from '@ember/service'; 3 import Component from '@ember/component'; 4 import { computed } from '@ember/object'; 5 import { run } from '@ember/runloop'; 6 import { lazyClick } from '../helpers/lazy-click'; 7 import { task, timeout } from 'ember-concurrency'; 8 9 export default Component.extend({ 10 store: service(), 11 12 tagName: 'tr', 13 14 classNames: ['allocation-row', 'is-interactive'], 15 16 allocation: null, 17 18 // Used to determine whether the row should mention the node or the job 19 context: null, 20 21 backoffSequence: computed(() => [500, 800, 1300, 2100, 3400, 5500]), 22 23 // Internal state 24 stats: null, 25 statsError: false, 26 27 enablePolling: computed(() => !Ember.testing), 28 29 onClick() {}, 30 31 click(event) { 32 lazyClick([this.get('onClick'), event]); 33 }, 34 35 didReceiveAttrs() { 36 // TODO: Use this code again once the temporary workaround below 37 // is resolved. 38 39 // If the job for this allocation is incomplete, reload it to get 40 // detailed information. 41 // const allocation = this.get('allocation'); 42 // if ( 43 // allocation && 44 // allocation.get('job') && 45 // !allocation.get('job.isPending') && 46 // !allocation.get('taskGroup') 47 // ) { 48 // const job = allocation.get('job.content'); 49 // job && job.reload(); 50 // } 51 52 // TEMPORARY: https://github.com/emberjs/data/issues/5209 53 // Ember Data doesn't like it when relationships aren't reflective, 54 // which means the allocation's job will be null if it hasn't been 55 // resolved through the allocation (allocation.get('job')) before 56 // being resolved through the store (store.findAll('job')). The 57 // workaround is to persist the jobID as a string on the allocation 58 // and manually re-link the two records here. 59 const allocation = this.get('allocation'); 60 61 if (allocation) { 62 this.get('fetchStats').perform(allocation); 63 } else { 64 this.get('fetchStats').cancelAll(); 65 this.set('stats', null); 66 } 67 run.scheduleOnce('afterRender', this, qualifyJob); 68 }, 69 70 fetchStats: task(function*(allocation) { 71 const backoffSequence = this.get('backoffSequence').slice(); 72 const maxTiming = backoffSequence.pop(); 73 74 do { 75 try { 76 const stats = yield allocation.fetchStats(); 77 this.set('stats', stats); 78 this.set('statsError', false); 79 } catch (error) { 80 this.set('statsError', true); 81 } 82 yield timeout(backoffSequence.shift() || maxTiming); 83 } while (this.get('enablePolling')); 84 }).drop(), 85 }); 86 87 function qualifyJob() { 88 const allocation = this.get('allocation'); 89 if (allocation.get('originalJobId')) { 90 const job = this.get('store').peekRecord('job', allocation.get('originalJobId')); 91 if (job) { 92 allocation.setProperties({ 93 job, 94 originalJobId: null, 95 }); 96 if (job.get('isPartial')) { 97 job.reload(); 98 } 99 } else { 100 this.get('store') 101 .findRecord('job', allocation.get('originalJobId')) 102 .then(job => { 103 allocation.set('job', job); 104 }); 105 } 106 } 107 }