diff --git a/src/renderer/api/kube-watch-api.ts b/src/renderer/api/kube-watch-api.ts index edf1ea89e6..ea451b4bf7 100644 --- a/src/renderer/api/kube-watch-api.ts +++ b/src/renderer/api/kube-watch-api.ts @@ -12,7 +12,7 @@ import { comparer, computed, observable, reaction } from "mobx"; import { autobind, EventEmitter } from "../utils"; import { ensureObjectSelfLink, KubeApi, parseKubeApi } from "./kube-api"; import { KubeJsonApiData, KubeJsonApiError } from "./kube-json-api"; -import { apiPrefix, isProduction } from "../../common/vars"; +import { apiPrefix, isDebugging, isProduction } from "../../common/vars"; import { apiManager } from "./api-manager"; export { IKubeWatchEvent, IKubeWatchEventStreamEnd }; @@ -29,6 +29,11 @@ export interface IKubeWatchSubscribeStoreOptions { waitUntilLoaded?: boolean; // subscribe only after loading all stores, default: true } +export interface IKubeWatchReconnectOptions { + reconnectAttempts: number; + timeout: number; +} + export interface IKubeWatchLog { message: string | Error; meta?: object; @@ -277,7 +282,10 @@ export class KubeWatchApi { break; case "STREAM_END": { - this.onServerStreamEnd(event as IKubeWatchEventStreamEnd); + this.onServerStreamEnd(event as IKubeWatchEventStreamEnd, { + reconnectAttempts: 5, + timeout: 1000, + }); break; } } @@ -285,35 +293,36 @@ export class KubeWatchApi { return message; } - protected async onServerStreamEnd(event: IKubeWatchEventStreamEnd) { + protected async onServerStreamEnd(event: IKubeWatchEventStreamEnd, opts?: IKubeWatchReconnectOptions) { const { apiBase, namespace } = parseKubeApi(event.url); const api = apiManager.getApi(apiBase); - if (api) { - try { - await api.refreshResourceVersion({ namespace }); - this.connect(); - } catch (error) { - this.log({ - message: new Error(`Failed to connect on single stream end: ${error}`), - meta: { event, error }, - }); + if (!api) return; - if (this.isActive) { - setTimeout(() => this.onServerStreamEnd(event), 1000); - } + try { + await api.refreshResourceVersion({ namespace }); + this.connect(); + } catch (error) { + this.log({ + message: new Error(`Failed to connect on single stream end: ${error}`), + meta: { event, error }, + }); + + if (this.isActive && opts?.reconnectAttempts > 0) { + opts.reconnectAttempts--; + setTimeout(() => this.onServerStreamEnd(event, opts), opts.timeout); // repeat event } } } protected log({ message, meta = {} }: IKubeWatchLog) { - if (isProduction) { + if (isProduction && !isDebugging) { return; } const logMessage = `%c[KUBE-WATCH-API]: ${String(message).toUpperCase()}`; const isError = message instanceof Error; - const textStyle = `font-weight: bold; ${isError ? "color: red;" : ""}`; + const textStyle = `font-weight: bold;`; const time = new Date().toLocaleString(); if (isError) { diff --git a/src/renderer/components/+events/event.store.ts b/src/renderer/components/+events/event.store.ts index 3651ce1549..d6090be947 100644 --- a/src/renderer/components/+events/event.store.ts +++ b/src/renderer/components/+events/event.store.ts @@ -52,6 +52,10 @@ export class EventStore extends KubeObjectStore { return compact(eventsWithError); } + + getWarningsCount() { + return this.getWarnings().length; + } } export const eventStore = new EventStore(); diff --git a/src/renderer/components/+namespaces/namespace.store.ts b/src/renderer/components/+namespaces/namespace.store.ts index 4636c4b525..63bb7525de 100644 --- a/src/renderer/components/+namespaces/namespace.store.ts +++ b/src/renderer/components/+namespaces/namespace.store.ts @@ -122,7 +122,7 @@ export class NamespaceStore extends KubeObjectStore { // if user has given static list of namespaces let's not start watches because watch adds stuff that's not wanted if (accessibleNamespaces.length > 0) { - return []; // no-op + return []; } return super.getSubscribeApis(); diff --git a/src/renderer/components/+nodes/nodes.store.ts b/src/renderer/components/+nodes/nodes.store.ts index c0385b078b..b301015747 100644 --- a/src/renderer/components/+nodes/nodes.store.ts +++ b/src/renderer/components/+nodes/nodes.store.ts @@ -1,3 +1,4 @@ +import { sum } from "lodash"; import { action, computed, observable } from "mobx"; import { clusterApi, IClusterMetrics, INodeMetrics, Node, nodesApi } from "../../api/endpoints"; import { autobind } from "../../utils"; @@ -62,6 +63,10 @@ export class NodesStore extends KubeObjectStore { }); } + getWarningsCount(): number { + return sum(this.items.map((node: Node) => node.getWarningConditions().length)); + } + reset() { super.reset(); this.metrics = {}; diff --git a/src/renderer/components/app.tsx b/src/renderer/components/app.tsx index a2aa0c8efe..2b739f787a 100755 --- a/src/renderer/components/app.tsx +++ b/src/renderer/components/app.tsx @@ -46,7 +46,6 @@ import { computed, reaction } from "mobx"; import { nodesStore } from "./+nodes/nodes.store"; import { podsStore } from "./+workloads-pods/pods.store"; import { kubeWatchApi } from "../api/kube-watch-api"; -import { sum } from "lodash"; import { ReplicaSetScaleDialog } from "./+workloads-replicasets/replicaset-scale-dialog"; @observer @@ -82,19 +81,14 @@ export class App extends React.Component { preload: true, }), - reaction(() => this.warningsCount, (count) => { + reaction(() => this.warningsTotal, (count: number) => { broadcastMessage(`cluster-warning-event-count:${getHostedCluster().id}`, count); }), ]); } - // todo: move to nodes-store.ts - @computed get warningsCount() { - let warnings = sum(nodesStore.items.map(node => node.getWarningConditions().length)); - - warnings = warnings + eventStore.getWarnings().length; - - return warnings; + @computed get warningsTotal(): number { + return nodesStore.getWarningsCount() + eventStore.getWarningsCount(); } get startURL() {