Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[3.x] Ability to see if a job is delayed #755

Merged
merged 10 commits into from
Feb 12, 2020
18 changes: 15 additions & 3 deletions resources/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,13 @@ import Routes from './routes';
import VueRouter from 'vue-router';
import VueJsonPretty from 'vue-json-pretty';

require('bootstrap');
window.Popper = require('popper.js').default;

try {
window.$ = window.jQuery = require('jquery');

require('bootstrap');
} catch (e) {}

let token = document.head.querySelector('meta[name="csrf-token"]');

Expand All @@ -17,8 +23,6 @@ if (token) {

Vue.use(VueRouter);

window.Popper = require('popper.js').default;

Vue.prototype.$http = axios.create();

window.Horizon.basePath = '/' + window.Horizon.path;
Expand All @@ -41,6 +45,14 @@ Vue.component('alert', require('./components/Alert.vue').default);

Vue.mixin(Base);

Vue.directive('tooltip', function(el, binding) {
$(el).tooltip({
title: binding.value,
placement: binding.arg,
trigger: 'hover',
});
});

new Vue({
el: '#horizon',

Expand Down
7 changes: 7 additions & 0 deletions resources/js/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,5 +45,12 @@ export default {
readableTimestamp(timestamp) {
return this.formatDate(timestamp).format('YYYY-MM-DD HH:mm:ss');
},

/**
* Convert to human readable timestamp e.g. "18 minutes".
*/
readableHumanTimestamp(timestamp) {
return this.formatDate(timestamp).fromNow(true);
},
},
};
2 changes: 0 additions & 2 deletions resources/js/components/Alert.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
<script type="text/ecmascript-6">
import $ from 'jquery';

export default {
props: ['type', 'message', 'autoClose', 'confirmationProceed', 'confirmationCancel'],

Expand Down
6 changes: 3 additions & 3 deletions resources/js/components/Stacktrace.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script type="text/ecmascript-6">
import _ from "lodash"
import _take from "lodash/take"

export default {
props: ['trace'],
Expand All @@ -16,7 +16,7 @@

computed: {
lines(){
return this.showAll ? _.take(this.trace, 1000) : _.take(this.trace, this.minimumLines);
return this.showAll ? _take(this.trace, 1000) : _take(this.trace, this.minimumLines);
}
}
}
Expand All @@ -38,4 +38,4 @@

<style scoped>

</style>
</style>
2 changes: 0 additions & 2 deletions resources/js/screens/monitoring/index.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
<script type="text/ecmascript-6">
import $ from 'jquery';

export default {
/**
* The component's data.
Expand Down
47 changes: 9 additions & 38 deletions resources/js/screens/recentJobs/index.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script type="text/ecmascript-6">
import $ from 'jquery';
import JobRow from './job-row';

export default {
/**
Expand All @@ -17,6 +17,13 @@
};
},

/**
* Components
*/
components: {
JobRow,
},

/**
* Prepare the component.
*/
Expand Down Expand Up @@ -168,43 +175,7 @@
</td>
</tr>

<tr v-for="job in jobs" :key="job.id">
<td>
<span v-if="job.status != 'failed'" :title="job.name">{{jobBaseName(job.name)}}</span>
<router-link v-if="job.status === 'failed'" :title="job.name" :to="{ name: 'failed-jobs-preview', params: { jobId: job.id }}">
{{ jobBaseName(job.name) }}
</router-link><br>

<small class="text-muted">
<router-link :to="{name: 'recent-jobs-preview', params: {jobId: job.id}}">View detail</router-link> |
Queue: {{job.queue}}
<span v-if="job.payload.tags.length">
| Tags: {{ job.payload.tags && job.payload.tags.length ? job.payload.tags.slice(0,3).join(', ') : '' }}<span v-if="job.payload.tags.length > 3"> ({{ job.payload.tags.length - 3 }} more)</span>
</span>
</small>
</td>
<td class="table-fit">
{{ readableTimestamp(job.payload.pushedAt) }}
</td>

<td class="table-fit">
<span>{{ job.completed_at ? (job.completed_at - job.reserved_at).toFixed(2)+'s' : '-' }}</span>
</td>

<td class="text-right table-fit">
<svg v-if="job.status == 'completed'" class="fill-success" viewBox="0 0 20 20" style="width: 1.5rem; height: 1.5rem;">
<path d="M2.93 17.07A10 10 0 1 1 17.07 2.93 10 10 0 0 1 2.93 17.07zm12.73-1.41A8 8 0 1 0 4.34 4.34a8 8 0 0 0 11.32 11.32zM6.7 9.29L9 11.6l4.3-4.3 1.4 1.42L9 14.4l-3.7-3.7 1.4-1.42z"></path>
</svg>

<svg v-if="job.status == 'reserved' || job.status == 'pending'" class="fill-warning" viewBox="0 0 20 20" style="width: 1.5rem; height: 1.5rem;">
<path d="M2.93 17.07A10 10 0 1 1 17.07 2.93 10 10 0 0 1 2.93 17.07zm12.73-1.41A8 8 0 1 0 4.34 4.34a8 8 0 0 0 11.32 11.32zM7 6h2v8H7V6zm4 0h2v8h-2V6z"/>
</svg>

<svg v-if="job.status == 'failed'" class="fill-danger" viewBox="0 0 20 20" style="width: 1.5rem; height: 1.5rem;">
<path d="M2.93 17.07A10 10 0 1 1 17.07 2.93 10 10 0 0 1 2.93 17.07zm1.41-1.41A8 8 0 1 0 15.66 4.34 8 8 0 0 0 4.34 15.66zm9.9-8.49L11.41 10l2.83 2.83-1.41 1.41L10 11.41l-2.83 2.83-1.41-1.41L8.59 10 5.76 7.17l1.41-1.41L10 8.59l2.83-2.83 1.41 1.41z"/>
</svg>
</td>
</tr>
<tr v-for="job in jobs" :key="job.id" :job="job" is="job-row"></tr>
</tbody>
</table>

Expand Down
71 changes: 71 additions & 0 deletions resources/js/screens/recentJobs/job-row.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<script type="text/ecmascript-6">
import phpunserialize from 'phpunserialize'
import moment from 'moment-timezone';

export default {
props: {
job: {
type: Object,
required: true
}
},

computed: {
unserialized() {
return phpunserialize(this.job.payload.data.command);
},

delayed() {
if(this.unserialized && this.unserialized.delay){
return moment.utc(this.unserialized.delay.date).fromNow(true);
}

return null;
},
},
}
</script>
<template>
<tr>
<td>
<span v-if="job.status != 'failed'" :title="job.name">{{jobBaseName(job.name)}}</span>
<router-link v-if="job.status === 'failed'" :title="job.name" :to="{ name: 'failed-jobs-preview', params: { jobId: job.id }}">
{{ jobBaseName(job.name) }}
</router-link>

{{ job.id }}

<small class="badge badge-secondary badge-sm" v-tooltip:top="`Delayed for ${delayed}`" v-if="delayed && (job.status == 'reserved' || job.status == 'pending')">Delayed</small>
<br>

<small class="text-muted">
<router-link :to="{name: 'recent-jobs-preview', params: {jobId: job.id}}">View detail</router-link> |
Queue: {{job.queue}}
<span v-if="job.payload.tags.length">
| Tags: {{ job.payload.tags && job.payload.tags.length ? job.payload.tags.slice(0,3).join(', ') : '' }}<span v-if="job.payload.tags.length > 3"> ({{ job.payload.tags.length - 3 }} more)</span>
</span>
</small>
</td>
<td class="table-fit">
{{ readableTimestamp(job.payload.pushedAt) }}
</td>

<td class="table-fit">
<span>{{ job.completed_at ? (job.completed_at - job.reserved_at).toFixed(2)+'s' : '-' }}</span>
</td>

<td class="text-right table-fit">
<svg v-if="job.status == 'completed'" class="fill-success" viewBox="0 0 20 20" style="width: 1.5rem; height: 1.5rem;">
<path d="M2.93 17.07A10 10 0 1 1 17.07 2.93 10 10 0 0 1 2.93 17.07zm12.73-1.41A8 8 0 1 0 4.34 4.34a8 8 0 0 0 11.32 11.32zM6.7 9.29L9 11.6l4.3-4.3 1.4 1.42L9 14.4l-3.7-3.7 1.4-1.42z"></path>
</svg>

<svg v-if="job.status == 'reserved' || job.status == 'pending'" class="fill-warning" viewBox="0 0 20 20" style="width: 1.5rem; height: 1.5rem;">
<path d="M2.93 17.07A10 10 0 1 1 17.07 2.93 10 10 0 0 1 2.93 17.07zm12.73-1.41A8 8 0 1 0 4.34 4.34a8 8 0 0 0 11.32 11.32zM7 6h2v8H7V6zm4 0h2v8h-2V6z"/>
</svg>

<svg v-if="job.status == 'failed'" class="fill-danger" viewBox="0 0 20 20" style="width: 1.5rem; height: 1.5rem;">
<path d="M2.93 17.07A10 10 0 1 1 17.07 2.93 10 10 0 0 1 2.93 17.07zm1.41-1.41A8 8 0 1 0 15.66 4.34 8 8 0 0 0 4.34 15.66zm9.9-8.49L11.41 10l2.83 2.83-1.41 1.41L10 11.41l-2.83 2.83-1.41-1.41L8.59 10 5.76 7.17l1.41-1.41L10 8.59l2.83-2.83 1.41 1.41z"/>
</svg>
</td>
</tr>
</template>
26 changes: 25 additions & 1 deletion resources/js/screens/recentJobs/job.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<script type="text/ecmascript-6">
import phpunserialize from 'phpunserialize'
import moment from "moment-timezone";

export default {
components: {
Expand All @@ -16,6 +17,20 @@
};
},

computed: {
unserialized() {
return phpunserialize(this.job.payload.data.command);
},

delayed() {
if(this.unserialized && this.unserialized.delay){
return moment.utc(this.unserialized.delay.date).local().format('YYYY-MM-DD HH:mm:ss');
}

return null;
},
},


/**
* Prepare the component.
Expand Down Expand Up @@ -81,9 +96,18 @@
<div class="col-md-2"><strong>Queue</strong></div>
<div class="col">{{job.queue}}</div>
</div>
<div class="row mb-2">
<div class="col-md-2"><strong>Pushed At</strong></div>
<div class="col">{{ readableTimestamp(job.payload.pushedAt) }}</div>
</div>
<div class="row mb-2" v-if="delayed">
<div class="col-md-2"><strong>Delayed Until</strong></div>
<div class="col">{{delayed}}</div>
</div>
<div class="row">
<div class="col-md-2"><strong>Completed At</strong></div>
<div class="col">{{readableTimestamp(job.completed_at)}}</div>
<div class="col" v-if="job.completed_at">{{readableTimestamp(job.completed_at)}}</div>
<div class="col" else>-</div>
</div>
</div>
</div>
Expand Down
4 changes: 4 additions & 0 deletions resources/sass/base.scss
Original file line number Diff line number Diff line change
Expand Up @@ -268,3 +268,7 @@ button:hover {
color: #fff;
background: $danger;
}

.badge-sm {
font-size: 0.75rem;
}