mirror of
https://github.com/ansible/awx.git
synced 2026-01-27 16:41:29 -03:30
229 lines
5.8 KiB
JavaScript
229 lines
5.8 KiB
JavaScript
const JOB_END = 'playbook_on_stats';
|
|
const MAX_LAG = 120;
|
|
|
|
function JobEventEngine ($q) {
|
|
this.init = ({ resource, scroll, page, onEventFrame, onStart, onStop }) => {
|
|
this.resource = resource;
|
|
this.scroll = scroll;
|
|
this.page = page;
|
|
|
|
this.lag = 0;
|
|
this.count = 0;
|
|
this.pageCount = 0;
|
|
this.chain = $q.resolve();
|
|
this.factors = this.getBatchFactors(this.resource.page.size);
|
|
|
|
this.state = {
|
|
started: false,
|
|
paused: false,
|
|
pausing: false,
|
|
resuming: false,
|
|
ending: false,
|
|
ended: false,
|
|
counting: false,
|
|
};
|
|
|
|
this.hooks = {
|
|
onEventFrame,
|
|
onStart,
|
|
onStop,
|
|
};
|
|
|
|
this.lines = {
|
|
used: [],
|
|
missing: [],
|
|
ready: false,
|
|
min: 0,
|
|
max: 0
|
|
};
|
|
};
|
|
|
|
this.setMinLine = min => {
|
|
if (min > this.lines.min) {
|
|
this.lines.min = min;
|
|
}
|
|
};
|
|
|
|
this.getBatchFactors = size => {
|
|
const factors = [1];
|
|
|
|
for (let i = 2; i <= size / 2; i++) {
|
|
if (size % i === 0) {
|
|
factors.push(i);
|
|
}
|
|
}
|
|
|
|
factors.push(size);
|
|
|
|
return factors;
|
|
};
|
|
|
|
this.getBatchFactorIndex = () => {
|
|
const index = Math.floor((this.lag / MAX_LAG) * this.factors.length);
|
|
|
|
return index > this.factors.length - 1 ? this.factors.length - 1 : index;
|
|
};
|
|
|
|
this.setBatchFrameCount = () => {
|
|
const index = this.getBatchFactorIndex();
|
|
|
|
this.framesPerRender = this.factors[index];
|
|
};
|
|
|
|
this.buffer = data => {
|
|
const pageAdded = this.page.addToBuffer(data);
|
|
|
|
this.pageCount++;
|
|
|
|
if (pageAdded) {
|
|
this.setBatchFrameCount();
|
|
|
|
if (this.isPausing()) {
|
|
this.pause(true);
|
|
} else if (this.isResuming()) {
|
|
this.resume(true);
|
|
}
|
|
}
|
|
};
|
|
|
|
this.checkLines = data => {
|
|
for (let i = data.start_line; i < data.end_line; i++) {
|
|
if (i > this.lines.max) {
|
|
this.lines.max = i;
|
|
}
|
|
|
|
this.lines.used.push(i);
|
|
}
|
|
|
|
const missing = [];
|
|
for (let i = this.lines.min; i < this.lines.max; i++) {
|
|
if (this.lines.used.indexOf(i) === -1) {
|
|
missing.push(i);
|
|
}
|
|
}
|
|
|
|
if (missing.length === 0) {
|
|
this.lines.ready = true;
|
|
this.lines.min = this.lines.max + 1;
|
|
this.lines.used = [];
|
|
} else {
|
|
this.lines.ready = false;
|
|
}
|
|
};
|
|
|
|
this.pushJobEvent = data => {
|
|
this.lag++;
|
|
|
|
this.chain = this.chain
|
|
.then(() => {
|
|
if (!this.isActive()) {
|
|
this.start();
|
|
} else if (data.event === JOB_END) {
|
|
if (this.isPaused()) {
|
|
this.end(true);
|
|
} else {
|
|
this.end();
|
|
}
|
|
}
|
|
|
|
this.checkLines(data);
|
|
this.buffer(data);
|
|
this.count++;
|
|
|
|
if (!this.isReadyToRender()) {
|
|
return $q.resolve();
|
|
}
|
|
|
|
const events = this.page.emptyBuffer();
|
|
this.count -= events.length;
|
|
|
|
return this.renderFrame(events);
|
|
})
|
|
.then(() => --this.lag);
|
|
|
|
return this.chain;
|
|
};
|
|
|
|
this.renderFrame = events => this.hooks.onEventFrame(events)
|
|
.then(() => {
|
|
if (this.isEnding()) {
|
|
const lastEvents = this.page.emptyBuffer();
|
|
|
|
if (lastEvents.length) {
|
|
return this.renderFrame(lastEvents);
|
|
}
|
|
|
|
this.end(true);
|
|
}
|
|
|
|
return $q.resolve();
|
|
});
|
|
|
|
this.resume = done => {
|
|
if (done) {
|
|
this.state.resuming = false;
|
|
this.state.paused = false;
|
|
} else if (!this.isTransitioning()) {
|
|
this.scroll.pause();
|
|
this.scroll.lock();
|
|
this.scroll.scrollToBottom();
|
|
this.state.resuming = true;
|
|
this.page.removeBookmark();
|
|
}
|
|
};
|
|
|
|
this.pause = done => {
|
|
if (done) {
|
|
this.state.pausing = false;
|
|
this.state.paused = true;
|
|
this.scroll.resume();
|
|
} else if (!this.isTransitioning()) {
|
|
this.scroll.pause();
|
|
this.scroll.unlock();
|
|
this.state.pausing = true;
|
|
this.page.setBookmark();
|
|
}
|
|
};
|
|
|
|
this.start = () => {
|
|
if (!this.state.ending && !this.state.ended) {
|
|
this.state.started = true;
|
|
this.scroll.pause();
|
|
this.scroll.lock();
|
|
|
|
this.hooks.onStart();
|
|
}
|
|
};
|
|
|
|
this.end = done => {
|
|
if (done) {
|
|
this.state.ending = false;
|
|
this.state.ended = true;
|
|
this.scroll.unlock();
|
|
this.scroll.resume();
|
|
|
|
this.hooks.onStop();
|
|
|
|
return;
|
|
}
|
|
|
|
this.state.ending = true;
|
|
};
|
|
|
|
this.isReadyToRender = () => this.isDone() ||
|
|
(!this.isPaused() && this.hasAllLines() && this.isBatchFull());
|
|
this.hasAllLines = () => this.lines.ready;
|
|
this.isBatchFull = () => this.count % this.framesPerRender === 0;
|
|
this.isPaused = () => this.state.paused;
|
|
this.isPausing = () => this.state.pausing;
|
|
this.isResuming = () => this.state.resuming;
|
|
this.isTransitioning = () => this.isActive() && (this.state.pausing || this.state.resuming);
|
|
this.isActive = () => this.state.started && !this.state.ended;
|
|
this.isEnding = () => this.state.ending;
|
|
this.isDone = () => this.state.ended;
|
|
}
|
|
|
|
JobEventEngine.$inject = ['$q'];
|
|
|
|
export default JobEventEngine;
|