Skip to content

Commit

Permalink
add total cpu/ram and fix race condition with polling interval for pr…
Browse files Browse the repository at this point in the history
…ocess manager closes amidaware/tacticalrmm#2037
  • Loading branch information
wh1te909 committed Oct 22, 2024
1 parent bdf7cd7 commit a8e5203
Showing 1 changed file with 117 additions and 88 deletions.
205 changes: 117 additions & 88 deletions src/components/agents/remotebg/ProcessManager.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,70 +17,85 @@
:loading="loading"
>
<template v-slot:top>
<q-btn
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">
<div class="q-gutter-md flex flex-center items-center">
<q-btn
:disable="pollInterval === 1"
v-if="isPolling"
dense
@click="pollIntervalChanged('subtract')"
flat
push
icon="remove"
size="sm"
color="grey"
@click="stopPoll"
icon="stop"
label="Stop Live Refresh"
/>
<q-btn
v-else
dense
flat
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"
@click="startPoll"
icon="play_arrow"
label="Resume Live Refresh"
/>
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>
<!-- file download doesn't work so disabling -->
<export-table-btn
v-show="false"
class="q-ml-sm"
:columns="columns"
:data="processes"
/>
<div class="flex flex-center q-ml-md">
<q-icon name="fas fa-microchip" class="q-mr-xs" />
<div class="text-caption q-mr-sm">
CPU Usage:
<span class="text-body1 text-weight-medium"
>{{ totalCpuUsage }}%</span
>
</div>

<q-icon name="fas fa-memory" class="q-mr-xs" />
<div class="text-caption">
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 v-slot:body="props">
<q-tr :props="props" class="cursor-pointer">
Expand Down Expand Up @@ -121,9 +136,6 @@ import {
import { bytes2Human } from "@/utils/format";
import { notifySuccess } from "@/utils/notify";
// ui imports
import ExportTableBtn from "@/components/ui/ExportTableBtn.vue";
const columns = [
{
name: "name",
Expand Down Expand Up @@ -164,7 +176,6 @@ const columns = [
];
export default {
components: { ExportTableBtn },
name: "ProcessManager",
props: {
agent_id: !String,
Expand All @@ -175,52 +186,71 @@ export default {
const poll = ref(null);
const isPolling = computed(() => !!poll.value);
async function startPoll() {
await getProcesses();
if (processes.value.length > 0) {
refreshProcesses();
}
function startPoll() {
stopPoll();
getProcesses();
poll.value = setInterval(() => {
getProcesses();
}, pollInterval.value * 1000);
}
function stopPoll() {
clearInterval(poll.value);
poll.value = null;
if (poll.value) {
clearInterval(poll.value);
poll.value = null;
}
}
function pollIntervalChanged(action) {
if (action === "subtract" && pollInterval.value <= 1) {
stopPoll();
startPoll();
return;
}
if (action === "add") {
pollInterval.value++;
} else {
} else if (action === "subtract" && pollInterval.value > 1) {
pollInterval.value--;
}
stopPoll();
startPoll();
if (isPolling.value) {
startPoll();
}
}
// process manager logic
const processes = ref([]);
const filter = ref("");
const memory = ref(null);
const total_ram = ref(0);
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() {
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;
}
function refreshProcesses() {
poll.value = setInterval(() => {
getProcesses(props.agent_id);
}, pollInterval.value * 1000);
}
async function killProcess(pid) {
loading.value = true;
let result = "";
Expand All @@ -235,11 +265,8 @@ export default {
// lifecycle hooks
onMounted(async () => {
memory.value = await fetchAgent(props.agent_id).total_ram;
await getProcesses();
if (processes.value.length > 0) {
refreshProcesses();
}
total_ram.value = (await fetchAgent(props.agent_id)).total_ram;
startPoll();
});
onBeforeUnmount(() => clearInterval(poll.value));
Expand All @@ -248,10 +275,12 @@ export default {
// reactive data
processes,
filter,
memory,
total_ram,
isPolling,
pollInterval,
loading,
totalCpuUsage,
totalRamUsage,
// non-reactive data
columns,
Expand Down

0 comments on commit a8e5203

Please sign in to comment.