From 89b7812fb41b57d1a0bd69d9a750c58964069480 Mon Sep 17 00:00:00 2001 From: IT-BillDeng Date: Mon, 27 Oct 2025 03:00:57 +0800 Subject: [PATCH] Improve master participation logic with fallback handling and UI messaging --- web/executionUtils.js | 4 +++- web/main.js | 14 ++++++++++- web/ui.js | 54 +++++++++++++++++++++++++++++++++---------- 3 files changed, 58 insertions(+), 14 deletions(-) diff --git a/web/executionUtils.js b/web/executionUtils.js index 453e2f6..c53a016 100644 --- a/web/executionUtils.js +++ b/web/executionUtils.js @@ -135,7 +135,9 @@ export async function executeParallelDistributed(extension, promptWrapper) { const wantsDelegate = Boolean(extension.config?.settings?.master_delegate_only); let masterDelegateActive = false; if (wantsDelegate) { - if (upscaleNodes.length > 0) { + if (activeWorkers.length === 0) { + extension.log("Master delegate-only mode disabled: no active workers detected. Falling back to master execution.", "debug"); + } else if (upscaleNodes.length > 0) { extension.log("Master delegate-only mode is not yet supported for UltimateSDUpscaleDistributed nodes. Falling back to normal execution.", "warn"); } else if (collectorNodes.length === 0) { extension.log("Master delegate-only mode requested but no DistributedCollector nodes found. Falling back to normal execution.", "debug"); diff --git a/web/main.js b/web/main.js index 0e3934c..f2c89ae 100644 --- a/web/main.js +++ b/web/main.js @@ -90,8 +90,16 @@ class DistributedExtension { return this.enabledWorkers.length > 0; } + isMasterParticipationEnabled() { + return !Boolean(this.config?.settings?.master_delegate_only); + } + + isMasterFallbackActive() { + return Boolean(this.config?.settings?.master_delegate_only) && this.enabledWorkers.length === 0; + } + isMasterParticipating() { - return !(this.config?.settings?.master_delegate_only); + return this.isMasterParticipationEnabled() || this.isMasterFallbackActive(); } async updateMasterParticipation(enabled) { @@ -163,6 +171,10 @@ class DistributedExtension { } catch (error) { this.log("Error updating worker: " + error.message, "error"); } + + if (this.panelElement) { + renderSidebarContent(this, this.panelElement); + } } async _updateSetting(key, value) { diff --git a/web/ui.js b/web/ui.js index 5444b7d..04d5a8d 100644 --- a/web/ui.js +++ b/web/ui.js @@ -17,7 +17,14 @@ const cardConfigs = { const cudaDevice = extension.config?.master?.cuda_device ?? extension.masterCudaDevice; const cudaInfo = cudaDevice !== undefined ? `CUDA ${cudaDevice} • ` : ''; const port = window.location.port || (window.location.protocol === 'https:' ? '443' : '80'); - const delegateBadge = extension.isMasterParticipating() ? '' : `
Orchestrator-only mode`; + const participationEnabled = extension.isMasterParticipationEnabled(); + const fallbackActive = extension.isMasterFallbackActive(); + let delegateBadge = ''; + if (!participationEnabled) { + delegateBadge = fallbackActive + ? `
Fallback active • Master executing` + : `
Orchestrator-only mode`; + } return `${data?.name || extension.config?.master?.name || "Master"}
${cudaInfo}Port ${port}${delegateBadge}`; }, controls: { @@ -867,20 +874,32 @@ export class DistributedUI { const isMasterToggle = config?.masterToggle && typeof extension.isMasterParticipating === 'function'; if (isMasterToggle) { - const participating = extension.isMasterParticipating(); - checkbox.checked = participating; + const participationEnabled = extension.isMasterParticipationEnabled(); + const fallbackActive = extension.isMasterFallbackActive(); + const buildTitle = (enabled, fallback) => { + if (enabled) { + return "Master participating • Click to switch to orchestrator-only"; + } + if (fallback) { + return "No workers selected • Master fallback execution active"; + } + return "Master orchestrator-only • Click to re-enable participation"; + }; + + checkbox.checked = participationEnabled; checkbox.style.pointerEvents = "none"; column.style.cursor = "pointer"; - column.title = participating ? "Master participating • Click to switch to orchestrator-only" : "Master orchestrator-only • Click to re-enable participation"; + column.title = buildTitle(participationEnabled, fallbackActive); column.onclick = async (event) => { if (event) { event.stopPropagation(); event.preventDefault(); } - const targetState = !checkbox.checked; - checkbox.checked = targetState; - column.title = targetState ? "Master participating • Click to switch to orchestrator-only" : "Master orchestrator-only • Click to re-enable participation"; - await extension.updateMasterParticipation(targetState); + const nextState = !extension.isMasterParticipationEnabled(); + const nextFallback = !nextState && extension.enabledWorkers.length === 0; + checkbox.checked = nextState; + column.title = buildTitle(nextState, nextFallback); + await extension.updateMasterParticipation(nextState); }; } else if (config?.enabled && !config?.disabled && data?.id) { checkbox.style.pointerEvents = "none"; @@ -955,14 +974,25 @@ export class DistributedUI { controlsWrapper.style.cssText = this.styles.controlsWrapper; if (config.type === 'master') { - const participating = extension.isMasterParticipating(); - const message = participating ? "Master participating in workflows" : "Master disabled: running as orchestrator only"; + const participationEnabled = extension.isMasterParticipationEnabled(); + const fallbackActive = extension.isMasterFallbackActive(); + let message; const badge = document.createElement("div"); badge.style.cssText = this.styles.infoBox; - badge.textContent = message; - if (!participating) { + if (fallbackActive) { + message = "No workers selected. Master fallback execution active."; + badge.textContent = message; + badge.style.backgroundColor = "#243024"; + badge.style.color = "#6bd06b"; + badge.style.border = "1px solid #335533"; + } else if (!participationEnabled) { + message = "Master disabled: running as orchestrator only."; + badge.textContent = message; badge.style.backgroundColor = "#3a3a3a"; badge.style.color = "#ffcc66"; + } else { + message = "Master participating in workflows."; + badge.textContent = message; } controlsWrapper.appendChild(badge); } else if (config.dynamic && data) {