add total cpu/ram and fix race condition with polling interval for process manager closes amidaware/tacticalrmm#2037

This commit is contained in:
wh1te909
2024-10-22 07:05:43 +00:00
parent bdf7cd7bf4
commit a8e5203b58

View File

@@ -17,70 +17,85 @@
:loading="loading" :loading="loading"
> >
<template v-slot:top> <template v-slot:top>
<q-btn <div class="q-gutter-md flex flex-center items-center">
v-if="isPolling"
dense
flat
push
@click="stopPoll"
icon="stop"
label="Stop Live Refresh"
/>
<q-btn
v-else
dense
flat
push
@click="startPoll"
icon="play_arrow"
label="Resume Live Refresh"
/>
<q-space />
<div class="q-pa-md q-gutter-sm">
<q-btn <q-btn
:disable="pollInterval === 1" v-if="isPolling"
dense dense
@click="pollIntervalChanged('subtract')" flat
push push
icon="remove" @click="stopPoll"
size="sm" icon="stop"
color="grey" label="Stop Live Refresh"
/> />
<q-btn <q-btn
v-else
dense dense
flat
push push
icon="add" @click="startPoll"
size="sm" icon="play_arrow"
color="grey" label="Resume Live Refresh"
@click="pollIntervalChanged('add')"
/> />
</div>
<div class="text-overline">
<q-badge
align="middle"
size="sm"
class="text-h6"
color="blue"
:label="pollInterval"
/>
Refresh interval (seconds)
</div>
<q-space /> <div class="flex flex-center q-ml-md">
<q-input v-model="filter" outlined label="Search" dense clearable> <q-icon name="fas fa-microchip" class="q-mr-xs" />
<template v-slot:prepend> <div class="text-caption q-mr-sm">
<q-icon name="search" /> CPU Usage:
</template> <span class="text-body1 text-weight-medium"
</q-input> >{{ totalCpuUsage }}%</span
<!-- file download doesn't work so disabling --> >
<export-table-btn </div>
v-show="false"
class="q-ml-sm" <q-icon name="fas fa-memory" class="q-mr-xs" />
:columns="columns" <div class="text-caption">
:data="processes" RAM Usage:
/> <span class="text-body1 text-weight-medium"
>{{ bytes2Human(totalRamUsage) }}/{{ total_ram }} GB</span
>
</div>
</div>
<q-space />
<div class="q-pa-md q-gutter-sm">
<q-btn
:disable="pollInterval === 1"
dense
@click="pollIntervalChanged('subtract')"
push
icon="remove"
size="sm"
color="grey"
/>
<q-btn
dense
push
icon="add"
size="sm"
color="grey"
@click="pollIntervalChanged('add')"
/>
</div>
<div class="text-overline">
<q-badge
align="middle"
size="sm"
class="text-h6"
color="blue"
:label="pollInterval"
/>
Refresh interval (seconds)
</div>
<q-space />
<q-input v-model="filter" outlined label="Search" dense clearable>
<template v-slot:prepend>
<q-icon name="search" />
</template>
</q-input>
</div>
</template> </template>
<template v-slot:body="props"> <template v-slot:body="props">
<q-tr :props="props" class="cursor-pointer"> <q-tr :props="props" class="cursor-pointer">
@@ -121,9 +136,6 @@ import {
import { bytes2Human } from "@/utils/format"; import { bytes2Human } from "@/utils/format";
import { notifySuccess } from "@/utils/notify"; import { notifySuccess } from "@/utils/notify";
// ui imports
import ExportTableBtn from "@/components/ui/ExportTableBtn.vue";
const columns = [ const columns = [
{ {
name: "name", name: "name",
@@ -164,7 +176,6 @@ const columns = [
]; ];
export default { export default {
components: { ExportTableBtn },
name: "ProcessManager", name: "ProcessManager",
props: { props: {
agent_id: !String, agent_id: !String,
@@ -175,52 +186,71 @@ export default {
const poll = ref(null); const poll = ref(null);
const isPolling = computed(() => !!poll.value); const isPolling = computed(() => !!poll.value);
async function startPoll() { function startPoll() {
await getProcesses(); stopPoll();
if (processes.value.length > 0) { getProcesses();
refreshProcesses(); poll.value = setInterval(() => {
} getProcesses();
}, pollInterval.value * 1000);
} }
function stopPoll() { function stopPoll() {
clearInterval(poll.value); if (poll.value) {
poll.value = null; clearInterval(poll.value);
poll.value = null;
}
} }
function pollIntervalChanged(action) { function pollIntervalChanged(action) {
if (action === "subtract" && pollInterval.value <= 1) {
stopPoll();
startPoll();
return;
}
if (action === "add") { if (action === "add") {
pollInterval.value++; pollInterval.value++;
} else { } else if (action === "subtract" && pollInterval.value > 1) {
pollInterval.value--; pollInterval.value--;
} }
stopPoll(); if (isPolling.value) {
startPoll(); startPoll();
}
} }
// process manager logic // process manager logic
const processes = ref([]); const processes = ref([]);
const filter = ref(""); const filter = ref("");
const memory = ref(null); const total_ram = ref(0);
const loading = ref(false); const loading = ref(false);
const totalCpuUsage = computed(() => {
if (!Array.isArray(processes.value) || processes.value.length === 0) {
return "0.00";
}
const total = processes.value.reduce((acc, proc) => {
const cpuPercent = parseFloat(proc.cpu_percent);
if (isNaN(cpuPercent)) {
return acc;
}
return acc + cpuPercent;
}, 0);
return total.toFixed(2);
});
const totalRamUsage = computed(() => {
return processes.value.reduce((acc, proc) => acc + proc.membytes, 0);
});
async function getProcesses() { async function getProcesses() {
loading.value = true; loading.value = true;
processes.value = await fetchAgentProcesses(props.agent_id); try {
processes.value = await fetchAgentProcesses(props.agent_id);
} catch (error) {
console.error(error);
}
loading.value = false; loading.value = false;
} }
function refreshProcesses() {
poll.value = setInterval(() => {
getProcesses(props.agent_id);
}, pollInterval.value * 1000);
}
async function killProcess(pid) { async function killProcess(pid) {
loading.value = true; loading.value = true;
let result = ""; let result = "";
@@ -235,11 +265,8 @@ export default {
// lifecycle hooks // lifecycle hooks
onMounted(async () => { onMounted(async () => {
memory.value = await fetchAgent(props.agent_id).total_ram; total_ram.value = (await fetchAgent(props.agent_id)).total_ram;
await getProcesses(); startPoll();
if (processes.value.length > 0) {
refreshProcesses();
}
}); });
onBeforeUnmount(() => clearInterval(poll.value)); onBeforeUnmount(() => clearInterval(poll.value));
@@ -248,10 +275,12 @@ export default {
// reactive data // reactive data
processes, processes,
filter, filter,
memory, total_ram,
isPolling, isPolling,
pollInterval, pollInterval,
loading, loading,
totalCpuUsage,
totalRamUsage,
// non-reactive data // non-reactive data
columns, columns,