Refactoring
This commit is contained in:
		
							parent
							
								
									72fb23f4d5
								
							
						
					
					
						commit
						85d8e6f220
					
				
					 3 changed files with 225 additions and 192 deletions
				
			
		
							
								
								
									
										181
									
								
								src/client/app/admin/views/queue.chart.vue
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										181
									
								
								src/client/app/admin/views/queue.chart.vue
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,181 @@ | |||
| <template> | ||||
| <div> | ||||
| 	<ui-info warn v-if="latestStats && latestStats.waiting > 0">The queue is jammed.</ui-info> | ||||
| 	<ui-horizon-group inputs v-if="latestStats" class="fit-bottom"> | ||||
| 		<ui-input :value="latestStats.activeSincePrevTick | number" type="text" readonly> | ||||
| 			<span>Process</span> | ||||
| 			<template #prefix><fa :icon="fasPlayCircle"/></template> | ||||
| 			<template #suffix>jobs/tick</template> | ||||
| 		</ui-input> | ||||
| 		<ui-input :value="latestStats.active | number" type="text" readonly> | ||||
| 			<span>Active</span> | ||||
| 			<template #prefix><fa :icon="farPlayCircle"/></template> | ||||
| 			<template #suffix>jobs</template> | ||||
| 		</ui-input> | ||||
| 		<ui-input :value="latestStats.waiting | number" type="text" readonly> | ||||
| 			<span>Waiting</span> | ||||
| 			<template #prefix><fa :icon="faStopCircle"/></template> | ||||
| 			<template #suffix>jobs</template> | ||||
| 		</ui-input> | ||||
| 		<ui-input :value="latestStats.delayed | number" type="text" readonly> | ||||
| 			<span>Delayed</span> | ||||
| 			<template #prefix><fa :icon="faStopwatch"/></template> | ||||
| 			<template #suffix>jobs</template> | ||||
| 		</ui-input> | ||||
| 	</ui-horizon-group> | ||||
| 	<div ref="chart" class="wptihjuy"></div> | ||||
| </div> | ||||
| </template> | ||||
| 
 | ||||
| <script lang="ts"> | ||||
| import Vue from 'vue'; | ||||
| import i18n from '../../i18n'; | ||||
| import ApexCharts from 'apexcharts'; | ||||
| import * as tinycolor from 'tinycolor2'; | ||||
| import { faStopwatch, faPlayCircle as fasPlayCircle } from '@fortawesome/free-solid-svg-icons'; | ||||
| import { faStopCircle, faPlayCircle as farPlayCircle } from '@fortawesome/free-regular-svg-icons'; | ||||
| 
 | ||||
| export default Vue.extend({ | ||||
| 	i18n: i18n('admin/views/queue.vue'), | ||||
| 
 | ||||
| 	props: { | ||||
| 		type: { | ||||
| 			type: String, | ||||
| 			required: true | ||||
| 		}, | ||||
| 		connection: { | ||||
| 			required: true | ||||
| 		}, | ||||
| 		limit: { | ||||
| 			type: Number, | ||||
| 			required: true | ||||
| 		} | ||||
| 	}, | ||||
| 
 | ||||
| 	data() { | ||||
| 		return { | ||||
| 			stats: [], | ||||
| 			chart: null, | ||||
| 			faStopwatch, faStopCircle, farPlayCircle, fasPlayCircle | ||||
| 		}; | ||||
| 	}, | ||||
| 
 | ||||
| 	computed: { | ||||
| 		latestStats(): any { | ||||
| 			return this.stats.length > 0 ? this.stats[this.stats.length - 1][this.type] : null; | ||||
| 		} | ||||
| 	}, | ||||
| 
 | ||||
| 	watch: { | ||||
| 		stats(stats) { | ||||
| 			this.chart.updateSeries([{ | ||||
| 				name: 'Process', | ||||
| 				type: 'area', | ||||
| 				data: stats.map((x, i) => ({ x: i, y: x[this.type].activeSincePrevTick })) | ||||
| 			}, { | ||||
| 				name: 'Active', | ||||
| 				type: 'area', | ||||
| 				data: stats.map((x, i) => ({ x: i, y: x[this.type].active })) | ||||
| 			}, { | ||||
| 				name: 'Waiting', | ||||
| 				type: 'line', | ||||
| 				data: stats.map((x, i) => ({ x: i, y: x[this.type].waiting })) | ||||
| 			}, { | ||||
| 				name: 'Delayed', | ||||
| 				type: 'line', | ||||
| 				data: stats.map((x, i) => ({ x: i, y: x[this.type].delayed })) | ||||
| 			}]); | ||||
| 		}, | ||||
| 	}, | ||||
| 
 | ||||
| 	mounted() { | ||||
| 		this.chart = new ApexCharts(this.$refs.chart, { | ||||
| 			chart: { | ||||
| 				id: this.type, | ||||
| 				group: 'queue', | ||||
| 				type: 'area', | ||||
| 				height: 200, | ||||
| 				animations: { | ||||
| 					dynamicAnimation: { | ||||
| 						enabled: false | ||||
| 					} | ||||
| 				}, | ||||
| 				toolbar: { | ||||
| 					show: false | ||||
| 				}, | ||||
| 				zoom: { | ||||
| 					enabled: false | ||||
| 				} | ||||
| 			}, | ||||
| 			dataLabels: { | ||||
| 				enabled: false | ||||
| 			}, | ||||
| 			grid: { | ||||
| 				clipMarkers: false, | ||||
| 				borderColor: 'rgba(0, 0, 0, 0.1)', | ||||
| 				xaxis: { | ||||
| 					lines: { | ||||
| 						show: true, | ||||
| 					} | ||||
| 				}, | ||||
| 			}, | ||||
| 			stroke: { | ||||
| 				curve: 'straight', | ||||
| 				width: 2 | ||||
| 			}, | ||||
| 			tooltip: { | ||||
| 				enabled: false | ||||
| 			}, | ||||
| 			legend: { | ||||
| 				labels: { | ||||
| 					colors: tinycolor(getComputedStyle(document.documentElement).getPropertyValue('--text')).toRgbString() | ||||
| 				}, | ||||
| 			}, | ||||
| 			series: [] as any, | ||||
| 			colors: ['#00E396', '#00BCD4', '#FFB300', '#e53935'], | ||||
| 			xaxis: { | ||||
| 				type: 'numeric', | ||||
| 				labels: { | ||||
| 					show: false | ||||
| 				}, | ||||
| 				tooltip: { | ||||
| 					enabled: false | ||||
| 				} | ||||
| 			}, | ||||
| 			yaxis: { | ||||
| 				show: false, | ||||
| 				min: 0, | ||||
| 			} | ||||
| 		}); | ||||
| 
 | ||||
| 		this.chart.render(); | ||||
| 
 | ||||
| 		this.connection.on('stats', this.onStats); | ||||
| 		this.connection.on('statsLog', this.onStatsLog); | ||||
| 
 | ||||
| 		this.$once('hook:beforeDestroy', () => { | ||||
| 			if (this.chart) this.chart.destroy(); | ||||
| 		}); | ||||
| 	}, | ||||
| 
 | ||||
| 	methods: { | ||||
| 		onStats(stats) { | ||||
| 			this.stats.push(stats); | ||||
| 			if (this.stats.length > this.limit) this.stats.shift(); | ||||
| 		}, | ||||
| 
 | ||||
| 		onStatsLog(statsLog) { | ||||
| 			for (const stats of statsLog.reverse()) { | ||||
| 				this.onStats(stats); | ||||
| 			} | ||||
| 		}, | ||||
| 	} | ||||
| }); | ||||
| </script> | ||||
| 
 | ||||
| <style lang="stylus" scoped> | ||||
| .wptihjuy | ||||
| 	min-height 200px !important | ||||
| 	margin 0 -8px -8px -8px | ||||
| 
 | ||||
| </style> | ||||
|  | @ -4,57 +4,11 @@ | |||
| 		<template #title><fa :icon="faChartBar"/> {{ $t('title') }}</template> | ||||
| 		<section class="wptihjuy"> | ||||
| 			<header><fa :icon="faPaperPlane"/> Deliver</header> | ||||
| 			<ui-info warn v-if="latestStats && latestStats.deliver.waiting > 0">The queue is jammed.</ui-info> | ||||
| 			<ui-horizon-group inputs v-if="latestStats" class="fit-bottom"> | ||||
| 				<ui-input :value="latestStats.deliver.activeSincePrevTick | number" type="text" readonly> | ||||
| 					<span>Process</span> | ||||
| 					<template #prefix><fa :icon="fasPlayCircle"/></template> | ||||
| 					<template #suffix>jobs/tick</template> | ||||
| 				</ui-input> | ||||
| 				<ui-input :value="latestStats.deliver.active | number" type="text" readonly> | ||||
| 					<span>Active</span> | ||||
| 					<template #prefix><fa :icon="farPlayCircle"/></template> | ||||
| 					<template #suffix>jobs</template> | ||||
| 				</ui-input> | ||||
| 				<ui-input :value="latestStats.deliver.waiting | number" type="text" readonly> | ||||
| 					<span>Waiting</span> | ||||
| 					<template #prefix><fa :icon="faStopCircle"/></template> | ||||
| 					<template #suffix>jobs</template> | ||||
| 				</ui-input> | ||||
| 				<ui-input :value="latestStats.deliver.delayed | number" type="text" readonly> | ||||
| 					<span>Delayed</span> | ||||
| 					<template #prefix><fa :icon="faStopwatch"/></template> | ||||
| 					<template #suffix>jobs</template> | ||||
| 				</ui-input> | ||||
| 			</ui-horizon-group> | ||||
| 			<div ref="deliverChart" class="chart"></div> | ||||
| 			<x-chart v-if="connection" :connection="connection" :limit="chartLimit" type="deliver"/> | ||||
| 		</section> | ||||
| 		<section class="wptihjuy"> | ||||
| 			<header><fa :icon="faInbox"/> Inbox</header> | ||||
| 			<ui-info warn v-if="latestStats && latestStats.inbox.waiting > 0">The queue is jammed.</ui-info> | ||||
| 			<ui-horizon-group inputs v-if="latestStats" class="fit-bottom"> | ||||
| 				<ui-input :value="latestStats.inbox.activeSincePrevTick | number" type="text" readonly> | ||||
| 					<span>Process</span> | ||||
| 					<template #prefix><fa :icon="fasPlayCircle"/></template> | ||||
| 					<template #suffix>jobs/tick</template> | ||||
| 				</ui-input> | ||||
| 				<ui-input :value="latestStats.inbox.active | number" type="text" readonly> | ||||
| 					<span>Active</span> | ||||
| 					<template #prefix><fa :icon="farPlayCircle"/></template> | ||||
| 					<template #suffix>jobs</template> | ||||
| 				</ui-input> | ||||
| 				<ui-input :value="latestStats.inbox.waiting | number" type="text" readonly> | ||||
| 					<span>Waiting</span> | ||||
| 					<template #prefix><fa :icon="faStopCircle"/></template> | ||||
| 					<template #suffix>jobs</template> | ||||
| 				</ui-input> | ||||
| 				<ui-input :value="latestStats.inbox.delayed | number" type="text" readonly> | ||||
| 					<span>Delayed</span> | ||||
| 					<template #prefix><fa :icon="faStopwatch"/></template> | ||||
| 					<template #suffix>jobs</template> | ||||
| 				</ui-input> | ||||
| 			</ui-horizon-group> | ||||
| 			<div ref="inboxChart" class="chart"></div> | ||||
| 			<x-chart v-if="connection" :connection="connection" :limit="chartLimit" type="inbox"/> | ||||
| 		</section> | ||||
| 		<section> | ||||
| 			<ui-button @click="removeAllJobs">{{ $t('remove-all-jobs') }}</ui-button> | ||||
|  | @ -94,74 +48,31 @@ | |||
| 
 | ||||
| <script lang="ts"> | ||||
| import Vue from 'vue'; | ||||
| import { faTasks, faInbox } from '@fortawesome/free-solid-svg-icons'; | ||||
| import { faPaperPlane, faChartBar } from '@fortawesome/free-regular-svg-icons'; | ||||
| import i18n from '../../i18n'; | ||||
| import ApexCharts from 'apexcharts'; | ||||
| import * as tinycolor from 'tinycolor2'; | ||||
| import { faTasks, faInbox, faStopwatch, faPlayCircle as fasPlayCircle } from '@fortawesome/free-solid-svg-icons'; | ||||
| import { faPaperPlane, faStopCircle, faPlayCircle as farPlayCircle, faChartBar } from '@fortawesome/free-regular-svg-icons'; | ||||
| 
 | ||||
| const limit = 200; | ||||
| import XChart from './queue.chart.vue'; | ||||
| 
 | ||||
| export default Vue.extend({ | ||||
| 	i18n: i18n('admin/views/queue.vue'), | ||||
| 
 | ||||
| 	components: { | ||||
| 		XChart | ||||
| 	}, | ||||
| 
 | ||||
| 	data() { | ||||
| 		return { | ||||
| 			stats: [], | ||||
| 			deliverChart: null, | ||||
| 			inboxChart: null, | ||||
| 			connection: null, | ||||
| 			chartLimit: 200, | ||||
| 			jobs: [], | ||||
| 			jobsLimit: 50, | ||||
| 			domain: 'deliver', | ||||
| 			state: 'delayed', | ||||
| 			faTasks, faPaperPlane, faInbox, faStopwatch, faStopCircle, farPlayCircle, fasPlayCircle, faChartBar | ||||
| 			faTasks, faPaperPlane, faInbox, faChartBar | ||||
| 		}; | ||||
| 	}, | ||||
| 
 | ||||
| 	computed: { | ||||
| 		latestStats(): any { | ||||
| 			return this.stats[this.stats.length - 1]; | ||||
| 		} | ||||
| 	}, | ||||
| 
 | ||||
| 	watch: { | ||||
| 		stats(stats) { | ||||
| 			this.inboxChart.updateSeries([{ | ||||
| 				name: 'Process', | ||||
| 				type: 'area', | ||||
| 				data: stats.map((x, i) => ({ x: i, y: x.inbox.activeSincePrevTick })) | ||||
| 			}, { | ||||
| 				name: 'Active', | ||||
| 				type: 'area', | ||||
| 				data: stats.map((x, i) => ({ x: i, y: x.inbox.active })) | ||||
| 			}, { | ||||
| 				name: 'Waiting', | ||||
| 				type: 'line', | ||||
| 				data: stats.map((x, i) => ({ x: i, y: x.inbox.waiting })) | ||||
| 			}, { | ||||
| 				name: 'Delayed', | ||||
| 				type: 'line', | ||||
| 				data: stats.map((x, i) => ({ x: i, y: x.inbox.delayed })) | ||||
| 			}]); | ||||
| 			this.deliverChart.updateSeries([{ | ||||
| 				name: 'Process', | ||||
| 				type: 'area', | ||||
| 				data: stats.map((x, i) => ({ x: i, y: x.deliver.activeSincePrevTick })) | ||||
| 			}, { | ||||
| 				name: 'Active', | ||||
| 				type: 'area', | ||||
| 				data: stats.map((x, i) => ({ x: i, y: x.deliver.active })) | ||||
| 			}, { | ||||
| 				name: 'Waiting', | ||||
| 				type: 'line', | ||||
| 				data: stats.map((x, i) => ({ x: i, y: x.deliver.waiting })) | ||||
| 			}, { | ||||
| 				name: 'Delayed', | ||||
| 				type: 'line', | ||||
| 				data: stats.map((x, i) => ({ x: i, y: x.deliver.delayed })) | ||||
| 			}]); | ||||
| 		}, | ||||
| 
 | ||||
| 		domain() { | ||||
| 			this.jobs = []; | ||||
| 			this.fetchJobs(); | ||||
|  | @ -176,83 +87,14 @@ export default Vue.extend({ | |||
| 	mounted() { | ||||
| 		this.fetchJobs(); | ||||
| 
 | ||||
| 		const chartOpts = id => ({ | ||||
| 			chart: { | ||||
| 				id, | ||||
| 				group: 'queue', | ||||
| 				type: 'area', | ||||
| 				height: 200, | ||||
| 				animations: { | ||||
| 					dynamicAnimation: { | ||||
| 						enabled: false | ||||
| 					} | ||||
| 				}, | ||||
| 				toolbar: { | ||||
| 					show: false | ||||
| 				}, | ||||
| 				zoom: { | ||||
| 					enabled: false | ||||
| 				} | ||||
| 			}, | ||||
| 			dataLabels: { | ||||
| 				enabled: false | ||||
| 			}, | ||||
| 			grid: { | ||||
| 				clipMarkers: false, | ||||
| 				borderColor: 'rgba(0, 0, 0, 0.1)', | ||||
| 				xaxis: { | ||||
| 					lines: { | ||||
| 						show: true, | ||||
| 					} | ||||
| 				}, | ||||
| 			}, | ||||
| 			stroke: { | ||||
| 				curve: 'straight', | ||||
| 				width: 2 | ||||
| 			}, | ||||
| 			tooltip: { | ||||
| 				enabled: false | ||||
| 			}, | ||||
| 			legend: { | ||||
| 				labels: { | ||||
| 					colors: tinycolor(getComputedStyle(document.documentElement).getPropertyValue('--text')).toRgbString() | ||||
| 				}, | ||||
| 			}, | ||||
| 			series: [] as any, | ||||
| 			colors: ['#00E396', '#00BCD4', '#FFB300', '#e53935'], | ||||
| 			xaxis: { | ||||
| 				type: 'numeric', | ||||
| 				labels: { | ||||
| 					show: false | ||||
| 				}, | ||||
| 				tooltip: { | ||||
| 					enabled: false | ||||
| 				} | ||||
| 			}, | ||||
| 			yaxis: { | ||||
| 				show: false, | ||||
| 				min: 0, | ||||
| 			} | ||||
| 		}); | ||||
| 
 | ||||
| 		this.inboxChart = new ApexCharts(this.$refs.inboxChart, chartOpts('a')); | ||||
| 		this.deliverChart = new ApexCharts(this.$refs.deliverChart, chartOpts('b')); | ||||
| 
 | ||||
| 		this.inboxChart.render(); | ||||
| 		this.deliverChart.render(); | ||||
| 
 | ||||
| 		const connection = this.$root.stream.useSharedConnection('queueStats'); | ||||
| 		connection.on('stats', this.onStats); | ||||
| 		connection.on('statsLog', this.onStatsLog); | ||||
| 		connection.send('requestLog', { | ||||
| 		this.connection = this.$root.stream.useSharedConnection('queueStats'); | ||||
| 		this.connection.send('requestLog', { | ||||
| 			id: Math.random().toString().substr(2, 8), | ||||
| 			length: limit | ||||
| 			length: this.chartLimit | ||||
| 		}); | ||||
| 
 | ||||
| 		this.$once('hook:beforeDestroy', () => { | ||||
| 			connection.dispose(); | ||||
| 			this.inboxChart.destroy(); | ||||
| 			this.deliverChart.destroy(); | ||||
| 			this.connection.dispose(); | ||||
| 		}); | ||||
| 	}, | ||||
| 
 | ||||
|  | @ -274,17 +116,6 @@ export default Vue.extend({ | |||
| 			}); | ||||
| 		}, | ||||
| 
 | ||||
| 		onStats(stats) { | ||||
| 			this.stats.push(stats); | ||||
| 			if (this.stats.length > limit) this.stats.shift(); | ||||
| 		}, | ||||
| 
 | ||||
| 		onStatsLog(statsLog) { | ||||
| 			for (const stats of statsLog.reverse()) { | ||||
| 				this.onStats(stats); | ||||
| 			} | ||||
| 		}, | ||||
| 
 | ||||
| 		fetchJobs() { | ||||
| 			this.$root.api('admin/queue/jobs', { | ||||
| 				domain: this.domain, | ||||
|  | @ -299,11 +130,6 @@ export default Vue.extend({ | |||
| </script> | ||||
| 
 | ||||
| <style lang="stylus" scoped> | ||||
| .wptihjuy | ||||
| 	> .chart | ||||
| 		min-height 200px !important | ||||
| 		margin 0 -8px | ||||
| 
 | ||||
| .xvvuvgsv | ||||
| 	> b | ||||
| 		margin-right 16px | ||||
|  |  | |||
|  | @ -1,6 +1,6 @@ | |||
| import * as Deque from 'double-ended-queue'; | ||||
| import Xev from 'xev'; | ||||
| import { deliverQueue, inboxQueue } from '../queue'; | ||||
| import { deliverQueue, inboxQueue, dbQueue, objectStorageQueue } from '../queue'; | ||||
| 
 | ||||
| const ev = new Xev(); | ||||
| 
 | ||||
|  | @ -18,6 +18,8 @@ export default function() { | |||
| 
 | ||||
| 	let activeDeliverJobs = 0; | ||||
| 	let activeInboxJobs = 0; | ||||
| 	let activeDbJobs = 0; | ||||
| 	let activeObjectStorageJobs = 0; | ||||
| 
 | ||||
| 	deliverQueue.on('global:active', () => { | ||||
| 		activeDeliverJobs++; | ||||
|  | @ -27,9 +29,19 @@ export default function() { | |||
| 		activeInboxJobs++; | ||||
| 	}); | ||||
| 
 | ||||
| 	dbQueue.on('global:active', () => { | ||||
| 		activeDbJobs++; | ||||
| 	}); | ||||
| 
 | ||||
| 	objectStorageQueue.on('global:active', () => { | ||||
| 		activeObjectStorageJobs++; | ||||
| 	}); | ||||
| 
 | ||||
| 	async function tick() { | ||||
| 		const deliverJobCounts = await deliverQueue.getJobCounts(); | ||||
| 		const inboxJobCounts = await inboxQueue.getJobCounts(); | ||||
| 		const dbJobCounts = await dbQueue.getJobCounts(); | ||||
| 		const objectStorageJobCounts = await objectStorageQueue.getJobCounts(); | ||||
| 
 | ||||
| 		const stats = { | ||||
| 			deliver: { | ||||
|  | @ -43,7 +55,19 @@ export default function() { | |||
| 				active: inboxJobCounts.active, | ||||
| 				waiting: inboxJobCounts.waiting, | ||||
| 				delayed: inboxJobCounts.delayed | ||||
| 			} | ||||
| 			}, | ||||
| 			db: { | ||||
| 				activeSincePrevTick: activeDbJobs, | ||||
| 				active: dbJobCounts.active, | ||||
| 				waiting: dbJobCounts.waiting, | ||||
| 				delayed: dbJobCounts.delayed | ||||
| 			}, | ||||
| 			objectStorage: { | ||||
| 				activeSincePrevTick: activeObjectStorageJobs, | ||||
| 				active: objectStorageJobCounts.active, | ||||
| 				waiting: objectStorageJobCounts.waiting, | ||||
| 				delayed: objectStorageJobCounts.delayed | ||||
| 			}, | ||||
| 		}; | ||||
| 
 | ||||
| 		ev.emit('queueStats', stats); | ||||
|  | @ -53,6 +77,8 @@ export default function() { | |||
| 
 | ||||
| 		activeDeliverJobs = 0; | ||||
| 		activeInboxJobs = 0; | ||||
| 		activeDbJobs = 0; | ||||
| 		activeObjectStorageJobs = 0; | ||||
| 	} | ||||
| 
 | ||||
| 	tick(); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue