Commit 5df1280b authored by Dillenn Terumalai's avatar Dillenn Terumalai
Browse files

// WIP

parent d3d8563e
<?php
if (! function_exists('job_path')) {
/**
* Get the path to the jobs folder.
*
* @param string $path
* @return string
*/
function job_path(string $path = ''): string
{
return storage_path('app/jobs').($path ? DIRECTORY_SEPARATOR.$path : $path);
}
}
......@@ -4,7 +4,8 @@
"keywords": [
"dterumal",
"laravel",
"laravel-cluster"
"laravel-cluster",
"cluster"
],
"type": "library",
"homepage": "https://github.com/dterumal/laravel-cluster",
......@@ -18,7 +19,10 @@
],
"require": {
"php": "^7.4|^8.0",
"ext-json": "*",
"illuminate/contracts": "^8.37",
"illuminate/support": "^8.37",
"nesbot/carbon": "^2.49",
"inertiajs/inertia-laravel": "^0.4.2"
},
"require-dev": {
......@@ -34,10 +38,7 @@
"psr-4": {
"Dterumal\\LaravelCluster\\": "src",
"Dterumal\\LaravelCluster\\Database\\Factories\\": "database/factories"
},
"files": [
"Helpers.php"
]
}
},
"autoload-dev": {
"psr-4": {
......@@ -58,5 +59,10 @@
"LaravelCluster": "Dterumal\\LaravelCluster\\LaravelClusterFacade"
}
}
}
},
"config": {
"sort-packages": true
},
"minimum-stability": "dev",
"prefer-stable": true
}
......@@ -1132,27 +1132,6 @@
"integrity": "sha512-Fxt+AfXgjMoin2maPIYzFZnQjAXjAL0PHscM5pRTtatFqB+vZxAM9tLp2Optnuw3QOQC40jTNeGYFOMvyf7v9g==",
"dev": true
},
"@inertiajs/inertia": {
"version": "0.9.2",
"resolved": "https://registry.npmjs.org/@inertiajs/inertia/-/inertia-0.9.2.tgz",
"integrity": "sha512-itHzyc/Qq3zd9GZPkL5vbd2ir7BELHalablNptvHkiJ1rU/WGI8Fdh1zjZIVBEmqB/EjA6YGoUVl3ftYFP1uoQ==",
"dev": true,
"requires": {
"axios": "^0.21.1",
"deepmerge": "^4.0.0",
"qs": "^6.9.0"
}
},
"@inertiajs/inertia-vue": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/@inertiajs/inertia-vue/-/inertia-vue-0.6.2.tgz",
"integrity": "sha512-VZyRkvA85ok1qei1CM6w+3rPNVvrWWfEKUS6VZ/4TSD+EyRitUpPAB2owp2UiPk/TGhOBVsmSV578msfC8lmhQ==",
"dev": true,
"requires": {
"lodash.clonedeep": "^4.5.0",
"lodash.isequal": "^4.5.0"
}
},
"@mdi/font": {
"version": "5.9.55",
"resolved": "https://registry.npmjs.org/@mdi/font/-/font-5.9.55.tgz",
......@@ -1383,12 +1362,6 @@
"integrity": "sha512-Fx+NpfOO0CpeYX2g9bkvX8O5qh9wrU1sOF4g8sft4Mu7z+qfe387YlyY8w8daDyDsKY5vUxM0yxkAYnbkRbZEw==",
"dev": true
},
"@types/ziggy-js": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@types/ziggy-js/-/ziggy-js-1.0.1.tgz",
"integrity": "sha512-ZnYSbq+8kx2CoddmD0J0lfoT9E3+MQ3FbylMek4j4ucfH2Ta+uj52cnDvM9IQ3ILGa5m2kL1assOhZ8qfzWE/A==",
"dev": true
},
"@vue/component-compiler-utils": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/@vue/component-compiler-utils/-/component-compiler-utils-3.2.2.tgz",
......@@ -2899,12 +2872,6 @@
"regexp.prototype.flags": "^1.2.0"
}
},
"deepmerge": {
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz",
"integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==",
"dev": true
},
"default-gateway": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz",
......@@ -4552,24 +4519,12 @@
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"dev": true
},
"lodash.clonedeep": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
"integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=",
"dev": true
},
"lodash.debounce": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
"integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=",
"dev": true
},
"lodash.isequal": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
"integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=",
"dev": true
},
"lodash.memoize": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
......@@ -5019,12 +4974,6 @@
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
"dev": true
},
"object-inspect": {
"version": "1.10.3",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.10.3.tgz",
"integrity": "sha512-e5mCJlSH7poANfC8z8S9s9S2IN5/4Zb3aZ33f5s8YqoazCFzNLloLU8r5VCG+G7WoqLvAAZoVMcy3tp/3X0Plw==",
"dev": true
},
"object-is": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz",
......@@ -5763,15 +5712,6 @@
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
"dev": true
},
"qs": {
"version": "6.10.1",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.10.1.tgz",
"integrity": "sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg==",
"dev": true,
"requires": {
"side-channel": "^1.0.4"
}
},
"querystring": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
......@@ -6373,17 +6313,6 @@
"integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==",
"dev": true
},
"side-channel": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
"integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
"dev": true,
"requires": {
"call-bind": "^1.0.0",
"get-intrinsic": "^1.0.2",
"object-inspect": "^1.9.0"
}
},
"signal-exit": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz",
......@@ -6980,6 +6909,12 @@
"integrity": "sha512-xYA8MkZynPBGd/w5QFJ2d/NM0z/YeegMqYTphy7NJQXbZcuU6FC6AOdUAcy4SXP+YnkerC6AfH+ldg7PDk9ESQ==",
"dev": true
},
"vue-router": {
"version": "3.5.2",
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.5.2.tgz",
"integrity": "sha512-807gn82hTnjCYGrnF3eNmIw/dk7/GE4B5h69BlyCK9KHASwSloD1Sjcn06zg9fVG4fYH2DrsNBZkpLtb25WtaQ==",
"dev": true
},
"vue-style-loader": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/vue-style-loader/-/vue-style-loader-4.1.3.tgz",
......@@ -7396,15 +7331,6 @@
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
"dev": true
},
"ziggy-js": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/ziggy-js/-/ziggy-js-1.3.1.tgz",
"integrity": "sha512-FhZdHYNV73/sjUGOwN3z/E/Tsus/FPd00ZawBGr7yG75Yw3s5CMfRgC0ziC9mHUXBZB8qsC/3ZJT1FRS96w3ew==",
"dev": true,
"requires": {
"qs": "^6.8.0"
}
}
}
}
This diff is collapsed.
{
"/js/app.js": "/js/app.js?id=237f7a475c00d8b9bc83"
"/js/app.js": "/js/app.js?id=6150589d40b63358ac09"
}
......@@ -12,6 +12,7 @@
v-if="items.length"
:headers="headers"
:items="items"
:loading="isLoading"
hide-default-footer
>
<template
......@@ -19,7 +20,7 @@
>
<div class="pa-3">
<a class="primary--text text-subtitle-1"
@click="$inertia.visit(route('cluster.cancelled.show', item.id))">{{
@click="$router.push({ name: 'cancelled-job-detail', params: {id: item.id}})">{{
item.job_name.toUpperCase()
}}</a>
<p class="text-caption grey--text text--darken-1 mb-0">Partition: {{ item.partition }} | ID:
......@@ -34,14 +35,16 @@
<script lang="ts">
import 'reflect-metadata'
import {Component, Prop, Vue} from 'vue-property-decorator'
import {Component, Vue} from 'vue-property-decorator'
import ClusterLayout from '@/Layouts/ClusterLayout.vue'
@Component({
components: {ClusterLayout}
})
export default class CancelledJobs extends Vue {
@Prop() readonly items: any
isLoading: boolean = false
items: any
headers: any = [
{
......@@ -61,8 +64,22 @@ export default class CancelledJobs extends Vue {
}
]
loadJobs() {
this.isLoading = true
this.$http.get(`${window.LaravelCluster.basePath}/api/jobs/cancelled`)
.then(({data}) => {
this.items = data.jobs
})
.finally(() => {
this.isLoading = false
})
}
mounted() {
document.title = "LaravelCluster - Cancelled Jobs"
this.loadJobs()
}
}
</script>
......
......@@ -12,13 +12,14 @@
v-if="items.length"
:headers="headers"
:items="items"
:loading="isLoading"
hide-default-footer
>
<template
v-slot:item.job="{ item }"
>
<div class="pa-3">
<a class="primary--text text-subtitle-1" @click="$inertia.visit(route('cluster.completed.show', item.id))">{{
<a class="primary--text text-subtitle-1" @click="$router.push({ name: 'completed-job-detail', params: {id: item.id}})">{{
item.job_name.toUpperCase()
}}</a>
<p class="text-caption grey--text text--darken-1 mb-0">Partition: {{ item.partition }} | ID:
......@@ -40,7 +41,9 @@ import ClusterLayout from '@/Layouts/ClusterLayout.vue'
components: { ClusterLayout }
})
export default class CompletedJobs extends Vue {
@Prop() readonly items: any
isLoading: boolean = false
items: any
headers: any = [
{
......@@ -65,8 +68,22 @@ export default class CompletedJobs extends Vue {
}
]
loadJobs() {
this.isLoading = true
this.$http.get(`${window.LaravelCluster.basePath}/api/completed`)
.then(({data}) => {
this.items = data.jobs
})
.finally(() => {
this.isLoading = false
})
}
mounted() {
document.title = "LaravelCluster - Completed Jobs"
this.loadJobs()
}
}
</script>
......
......@@ -44,7 +44,7 @@
<v-data-table
:headers="headers"
:items="nodes"
:loading="isLoading"
hide-default-footer
></v-data-table>
</v-card-text>
......@@ -54,18 +54,20 @@
<script lang="ts">
import 'reflect-metadata'
import { Component, Prop, Vue } from 'vue-property-decorator'
import {Component, Vue} from 'vue-property-decorator'
import ClusterLayout from '@/Layouts/ClusterLayout.vue'
@Component({
components: { ClusterLayout }
})
export default class Dashboard extends Vue {
@Prop() readonly totalJobs: number
@Prop() readonly jobsPastHour: number
@Prop() readonly failedJobs: number
@Prop() readonly isOnline: boolean
@Prop() readonly nodes: any
isLoading: boolean = false
totalJobs: number
jobsPastHour: number
failedJobs: number
isOnline: boolean
nodes: any[]
headers: any = [
{
......@@ -100,6 +102,22 @@ export default class Dashboard extends Vue {
}
]
loadStats() {
this.isLoading = true
this.$http.get(`${window.LaravelCluster.basePath}/api/dashboard`)
.then(({data}) => {
this.totalJobs = data.totalJobs
this.jobsPastHour = data.jobsPastHour
this.failedJobs = data.failedJobs
this.isOnline = data.isOnline
this.nodes = data.nodes
})
.finally(() => {
this.isLoading = false
})
}
mounted() {
document.title = "LaravelCluster - Dashboard"
}
......
......@@ -12,13 +12,14 @@
v-if="items.length"
:headers="headers"
:items="items"
:loading="isLoading"
hide-default-footer
>
<template
v-slot:item.job="{ item }"
>
<div class="pa-3">
<a class="primary--text text-subtitle-1" @click="$inertia.visit(route('cluster.failed.show', item.id))">{{
<a class="primary--text text-subtitle-1" @click="$router.push({ name: 'failed-job-detail', params: {id: item.id}})">{{
item.job_name.toUpperCase()
}}</a>
<p class="text-caption grey--text text--darken-1 mb-0">Partition: {{ item.partition }} | ID:
......@@ -40,7 +41,9 @@ import ClusterLayout from '@/Layouts/ClusterLayout.vue'
components: { ClusterLayout }
})
export default class FailedJobs extends Vue {
@Prop() readonly items: any
isLoading: boolean = false
items: any
headers: any = [
{
......@@ -65,8 +68,22 @@ export default class FailedJobs extends Vue {
}
]
loadJobs() {
this.isLoading = true
this.$http.get(`${window.LaravelCluster.basePath}/api/failed`)
.then(({data}) => {
this.items = data.queues
})
.finally(() => {
this.isLoading = false
})
}
mounted() {
document.title = "LaravelCluster - Failed Jobs"
this.loadJobs()
}
}
</script>
......
<template>
<cluster-layout>
<v-card class="mb-10">
<v-card class="mb-10" :loading="isLoading">
<v-card-title>
<p class="text-h6 mb-0">Inspector</p>
<v-spacer></v-spacer>
<v-spacer></v-spacer>
<v-spacer></v-spacer>
<v-text-field v-model="jobId" placeholder="Type job ID..." hide-details outlined dense></v-text-field>
<v-btn class="ml-3" color="primary" depressed @click="inspectJob()">Inspect</v-btn>
<v-btn class="ml-3" color="primary" depressed @click="inspect()">Inspect</v-btn>
</v-card-title>
<v-card-text class="px-0 pb-0">
<v-sheet color="black" dark class="pa-5">
......@@ -24,21 +24,29 @@
import 'reflect-metadata'
import {Component, Prop, Vue} from 'vue-property-decorator'
import ClusterLayout from '@/Layouts/ClusterLayout.vue'
import route from 'ziggy-js';
@Component({
components: {ClusterLayout}
})
export default class Inspector extends Vue {
@Prop() readonly information: string;
isLoading: boolean = false
information: string;
private jobId: string | null = null
inspectJob() {
this.$inertia.get(route('cluster.inspector'), {
inspect() {
this.$http.get(`${window.LaravelCluster.basePath}/api/inspector`, {
params: {
jobId: this.jobId
}
)
})
.then(({data}) => {
this.information = data.information
})
.finally(() => {
this.isLoading = false
})
}
get formattedInformation() {
......
......@@ -18,7 +18,7 @@
v-slot:item.job="{ item }"
>
<div class="pa-3">
<a class="primary--text text-subtitle-1" @click="$inertia.visit(route('cluster.pending.show', item.id))">{{
<a class="primary--text text-subtitle-1" @click="$router.push({ name: 'pending-job-detail', params: {id: item.id}})">{{
item.job_name.toUpperCase()
}}</a>
<p class="text-caption grey--text text--darken-1 mb-0">Partition: {{ item.partition }} | ID: {{ item.id }}</p>
......@@ -32,14 +32,16 @@
<script lang="ts">
import 'reflect-metadata'
import { Component, Prop, Vue } from 'vue-property-decorator'
import { Component, Vue } from 'vue-property-decorator'
import ClusterLayout from '@/Layouts/ClusterLayout.vue'
@Component({
components: { ClusterLayout }
})
export default class PendingJobs extends Vue {
@Prop() readonly items: any
isLoading: boolean = false
items: any
headers: any = [
{
......@@ -55,8 +57,22 @@ export default class PendingJobs extends Vue {
}
]
loadJobs() {
this.isLoading = true
this.$http.get(`${window.LaravelCluster.basePath}/api/failed`)
.then(({data}) => {
this.items = data.jobs
})
.finally(() => {
this.isLoading = false
})
}
mounted() {
document.title = "LaravelCluster - Pending Jobs"
this.loadJobs()
}
}
</script>
......
......@@ -8,7 +8,7 @@
<v-data-table
:headers="headers"
:items="queues"
:loading="isLoading"
hide-default-footer
></v-data-table>
</v-card-text>
......@@ -18,14 +18,16 @@
<script lang="ts">
import 'reflect-metadata'
import { Component, Prop, Vue } from 'vue-property-decorator'
import { Component, Vue } from 'vue-property-decorator'
import ClusterLayout from '@/Layouts/ClusterLayout.vue'
@Component({
components: { ClusterLayout }
})
export default class Queue extends Vue {
@Prop() readonly queues: any
isLoading: boolean = false
queues: any[]
headers: any = [
{
......@@ -70,6 +72,18 @@ export default class Queue extends Vue {
}
]
loadStats() {
this.isLoading = true
this.$http.get(`${window.LaravelCluster.basePath}/api/queue`)
.then(({data}) => {
this.queues = data.jobs
})
.finally(() => {
this.isLoading = false
})
}
mounted() {
document.title = "LaravelCluster - Queue"
}
......
<template>
<cluster-layout>
<v-card class="mb-10">
<v-card