From ca1b810c7bf53be88fdb99018624a310ccc7d298 Mon Sep 17 00:00:00 2001 From: Sean-McQ <37550899+Sean-McQ@users.noreply.github.com> Date: Fri, 13 Jan 2023 16:03:00 -0500 Subject: [PATCH] Moves sockets into the advanced worker (#7760) * Moves sockets into the advanced worker * worker can die peacefully now, making switching between cluster work. * Make waitFor generic, wire in to waitForTestFn * General Changes - Fixes for switching cluster - includes using common getPerformanceSetting - avoid new code to unsub before socket disconnect - handle `watch` `stop` requests - lots of TODO's (questions, work, checks, test, etc) - use common * Switch socket fixes - isAdvancedWorker should only be true for cluster store - advancedWorker to be wired in * Fix socket id for cluster workers - sockets use an incremented local var for id - when we nuke the socket file within the worker this resets, so they all ahve id of 1 - work around this by applying the unix time * Fix handling of new partical counts response - seen in dex cluster explorer dashboard - count cards would be removed when partial counts response received * Make resourceWatcher the sole location for watch state - getters canWatch, watchStarted now are worked around (they look at state in the UI thread) - we now don't call resource.stop or restart.start in subscription - tidied up `forgetType` - moved clearFromQueue from steve mutations into subscription mutations (better location) - added and removed some TODOs - fixed watch (stop handler should be higher up, include force watch handling) * pushes the csrf value into worker and adds it to fetch request headers. * refactors batchChanges to address ref concerns and be more performant * Maintain schema reference whilst updating - This change mutates input in a function, which is bad... - but ensures the reference isn't broken, which is needed to maintain similar functionality as before * Fix waitForTestFn - Seen when creating or viewing clusters * On unwatch ensure any pending watch requests are removed from the queue - the probably would have been a problem if the worker wasn't nuked - however as the codes there lets make it safe Also added `trace` feature in advanced worker, will probably bring out to other places as well * Fix navigation from cluster manager world to any cluster - Ensure that we handle the case where the advanced worker was created but the resource watcher wasn't - ... but fix case where this was happening (aka ensure that a blank cluster context is ignored) * Tidy some TODOs * Add perf settings page - This will help test normal flow (when advanced worker is disabled) - Note - setting is now in a bag. This may help us better support further settings (enable client side pagination, etc) ``` advancedWorker: { enabled: false }, ``` * FIX - Nav from cluster dashboard --> specific event --> cluster dashboard and events not re-subbed - Ensure we block default handling of resource.start (keep state in resource watcher) * Tidying up some TODOs * Adds in a cache and uses it to validate SCHEMA messages before batching. * Forgot to actually save CSRF to the resourceWatcher when instantiated. * an empty resource in a batchChange to signal remove * Move addSchemaIndexFields to and created removeSchemaIndexFields in new file - this avoids bringing class files into the worker * Fix disconnect/reconnect - Remove `syncWatch` (do the watch/unwatch straight away) - Test/Fix re-sub on reconnect - Test/Fix growls on disconnect * Tidying up some TODO's - including clean of workerQueue on resource.stop (this is SUPER defensive) * batchChanges will now handle aliases * Fix pods list - WIP - ensure podsByNamespace is updated on batchChange TODO - the final update to the pod is ignored - removing a namespace cleans the cache correctly - disabling advanced worker still works * Fix pods list - fixes - ensure podsByNamespace is updated on batchChange Tested / Fixed - the final update to the pod is ignored - removing a namespace cleans the cache correctly - disabling advanced worker still works * Tidying TODOs * Remove default same-origin header - https://developer.mozilla.org/en-US/docs/Web/API/Request/credentials * Fixed TODO description * Refactor subscribe, make it clear which vuex feature relates to what * Lots of Fixes - batchChanges fixes - fix index is 0 issues (!/!!index) - only `set` if we have to - ensure we set the correct index after pushing to list - ensure map is updated after reducing list size with limit - podsByNamespace fixes - ensure when ew replace... we don't use the same referenced object - general service resource fixes - ensure service's pods list stays up to date with store * Multiple improvements/fixes - resourceCache - store the hash instead of the whole object. This means longer load time be reduces memory footprint - resourceWatcher - don't re-sub on socket reconnect if watcher is in error - don't sub if watcher is in error - don't unwatch for 'failed to find schema' and 'too old' errors - this clears the error, we won't to keep it to ensure we don't watch - Remove #5997 comments, follow on work #7917 * toggle debug, remap alias types, cleaned up comments and console * Unit tests for batchChanges Much more scope for some crazy content * Logging tweaks - disable logging by default - initWorker comes in too late to affect initial trace, so just rely on the `debug` to toggle at runtime Co-authored-by: Richard Cox --- shell/assets/translations/en-us.yaml | 4 + shell/config/settings.ts | 3 +- shell/detail/service.vue | 11 +- shell/models/service.js | 27 +- .../pages/c/_cluster/settings/performance.vue | 16 + .../__tests__/mutations.spec.js | 406 ++++++++++++++++++ shell/plugins/dashboard-store/actions.js | 34 +- shell/plugins/dashboard-store/mutations.js | 136 +++++- .../plugins/dashboard-store/resource-class.js | 43 +- shell/plugins/steve/caches/resourceCache.js | 60 +++ shell/plugins/steve/getters.js | 15 +- shell/plugins/steve/mutations.js | 128 ++++-- shell/plugins/steve/resourceWatcher.js | 277 ++++++++++++ shell/plugins/steve/schema.utils.js | 25 ++ shell/plugins/steve/subscribe.js | 342 ++++++++++----- shell/plugins/steve/worker/index.js | 17 + .../steve/worker/web-worker.advanced.js | 302 +++++++++++++ .../web-worker.basic.js} | 27 +- shell/utils/async.ts | 36 ++ shell/utils/crypto/browserHashUtils.js | 18 + shell/utils/socket.js | 34 +- 21 files changed, 1685 insertions(+), 276 deletions(-) create mode 100644 shell/plugins/dashboard-store/__tests__/mutations.spec.js create mode 100644 shell/plugins/steve/caches/resourceCache.js create mode 100644 shell/plugins/steve/resourceWatcher.js create mode 100644 shell/plugins/steve/schema.utils.js create mode 100644 shell/plugins/steve/worker/index.js create mode 100644 shell/plugins/steve/worker/web-worker.advanced.js rename shell/plugins/steve/{web-worker.steve-sub-worker.js => worker/web-worker.basic.js} (85%) create mode 100644 shell/utils/async.ts diff --git a/shell/assets/translations/en-us.yaml b/shell/assets/translations/en-us.yaml index 3cae893b4eb..c8e7862dfeb 100644 --- a/shell/assets/translations/en-us.yaml +++ b/shell/assets/translations/en-us.yaml @@ -6813,6 +6813,10 @@ performance: count: inputLabel: Resource Threshold description: The threshold above which filtering by a namespace is required + advancedWorker: + label: Websocket Web Worker + description: Updates to resources pushed to the UI come via WebSocket and are handled in the UI thread. Enable this option to handle cluster WebSocket updates in a Web Worker in a separate thread. This should help the responsiveness of the UI in systems where resources change often. + checkboxLabel: Enable Advanced Websocket Web Worker banner: label: Fixed Banners diff --git a/shell/config/settings.ts b/shell/config/settings.ts index 73537e2603b..3e66b1d34e3 100644 --- a/shell/config/settings.ts +++ b/shell/config/settings.ts @@ -141,5 +141,6 @@ export const DEFAULT_PERF_SETTING = { forceNsFilter: { enabled: false, threshold: 1500, - } + }, + advancedWorker: { enabled: false }, }; diff --git a/shell/detail/service.vue b/shell/detail/service.vue index df9207f08b2..93ea34876e0 100644 --- a/shell/detail/service.vue +++ b/shell/detail/service.vue @@ -11,7 +11,6 @@ import Tab from '@shell/components/Tabbed/Tab'; import { CATTLE_PUBLIC_ENDPOINTS } from '@shell/config/labels-annotations'; import { KEY, VALUE } from '@shell/config/table-headers'; import { POD } from '@shell/config/types'; -import { allHash } from '@shell/utils/promise'; import { findBy } from '@shell/utils/array'; export default { @@ -36,13 +35,7 @@ export default { }, async fetch() { - const hash = { pods: this.value.pods() }; - - const res = await allHash(hash); - - for (const k in res) { - this[k] = res[k]; - } + await this.value.fetchPods(); }, data() { @@ -159,7 +152,7 @@ export default { :weight="4" > { - const podRelationship = (relationships || []).filter(relationship => relationship.toType === POD)[0]; - let pods = []; + return (relationships || []).filter(relationship => relationship.toType === POD)[0]; + } - if (podRelationship) { - pods = await this.$dispatch('cluster/findMatching', { - type: POD, - selector: podRelationship.selector, - namespace: this.namespace - }, { root: true }); - } + async fetchPods() { + if (this.podRelationship) { + await this.$dispatch('cluster/findMatching', { + type: POD, + selector: this.podRelationship.selector, + namespace: this.namespace + }, { root: true }); + } + } - return pods; - }; + get pods() { + return this.podRelationship ? this.$getters.matching( POD, this.podRelationship.selector, this.namespace ) : []; } get serviceType() { diff --git a/shell/pages/c/_cluster/settings/performance.vue b/shell/pages/c/_cluster/settings/performance.vue index 12577c317fc..b7999136690 100644 --- a/shell/pages/c/_cluster/settings/performance.vue +++ b/shell/pages/c/_cluster/settings/performance.vue @@ -267,6 +267,22 @@ export default { /> + +
+

{{ t('performance.advancedWorker.label') }}

+

{{ t('performance.advancedWorker.description') }}

+ + +