Files
mpuchstein 4f13f5c7c0 quickshell: speed up k8s refresh while the popout is open
While the popout is open, poll both status and metrics at a fast cadence
(kubeRefreshOpenMs, 3s) instead of 2min/15s, and refresh immediately when
it opens — so opening the pill shows fresh data and updates live. Status
reverts to the slow 2min pill cadence once closed.
2026-06-01 14:49:22 +02:00

125 lines
4.4 KiB
QML

pragma Singleton
import Quickshell
import Quickshell.Io
import QtQuick
Singleton {
id: root
property string status: "loading" // "loading" | "ok" | "degraded" | "error" | "stale"
property var pods: [] // Array of {app, ready, cpuM, memMi}
property int readyCount: 0
property int totalCount: 0
property var quota: null // quota object from metrics script
property int lastUpdatedSecs: 0 // seconds since last successful status fetch
Process {
id: statusProc
command: ["bash", Config.scriptsDir + "/k8s-status.sh", Config.kubeNamespace]
stdout: StdioCollector {
onStreamFinished: {
if (this.text.trim() === "") {
root.status = (root.status === "ok" || root.status === "degraded") ? "stale" : "error";
return;
}
try {
let data = JSON.parse(this.text);
// Preserve existing cpuM/memMi from last metrics fetch
let byApp = {};
for (let p of root.pods) byApp[p.app] = p;
root.pods = data.pods.map(p => ({
app: p.app,
ready: p.ready,
cpuM: byApp[p.app]?.cpuM ?? -1,
memMi: byApp[p.app]?.memMi ?? -1
}));
root.readyCount = data.readyCount;
root.totalCount = data.totalCount;
root.status = data.pods.every(p => p.ready) ? "ok" : "degraded";
root.lastUpdatedSecs = 0;
} catch(e) {
console.warn("Kubernetes: status parse error:", e);
root.status = (root.status === "ok" || root.status === "degraded") ? "stale" : "error";
}
}
}
}
Process {
id: metricsProc
command: ["bash", Config.scriptsDir + "/k8s-metrics.sh", Config.kubeNamespace]
stdout: StdioCollector {
onStreamFinished: {
if (this.text.trim() === "") return;
try {
let data = JSON.parse(this.text);
let byApp = {};
for (let m of data.podMetrics) byApp[m.app] = m;
root.pods = root.pods.map(p => ({
app: p.app,
ready: p.ready,
cpuM: byApp[p.app]?.cpuM ?? -1,
memMi: byApp[p.app]?.memMi ?? -1
}));
root.quota = data.quota;
} catch(e) {
console.warn("Kubernetes: metrics parse error:", e);
}
}
}
}
// Ticker: increments lastUpdatedSecs every second (only once status is known)
Timer {
interval: 1000
running: root.status !== "loading"
repeat: true
onTriggered: root.lastUpdatedSecs++
}
// Force an immediate refresh (status always; metrics only while the popout is
// open, where they're shown). Called on pill click and on popout open.
function refresh() {
statusProc.running = false; statusProc.running = true;
if (PopoutState.active === "kubernetes") {
metricsProc.running = false; metricsProc.running = true;
}
}
readonly property bool popoutOpen: PopoutState.active === "kubernetes"
onPopoutOpenChanged: if (popoutOpen) refresh()
// Status poller — slow while the popout is closed (just the pill), fast while open.
Timer {
interval: root.popoutOpen ? Config.kubeRefreshOpenMs : Config.kubeStatusRefreshMs
running: Config.kubeEnabled
repeat: true
onTriggered: statusProc.running = true
}
// Metrics poller — only while the popout is open, at the fast cadence.
Timer {
interval: Config.kubeRefreshOpenMs
running: Config.kubeEnabled && root.popoutOpen
repeat: true
onTriggered: metricsProc.running = true
}
// Staleness check: flip to "stale" if no successful fetch for >60s
Timer {
interval: 10000
running: true
repeat: true
onTriggered: {
if (root.lastUpdatedSecs > 60 && (root.status === "ok" || root.status === "degraded"))
root.status = "stale";
}
}
Component.onCompleted: {
if (Config.kubeEnabled)
statusProc.running = true;
}
}