/**
* Lightweight Maintenance Workflow for VRAM Management
*
* This workflow is designed to be extremely lightweight and trigger
* ComfyUI's LRU cache to evict heavy models (like FLUX) from VRAM.
*
* Strategy:
* - Uses only basic nodes (no model loading)
* - Creates a tiny blank image
* - Minimal processing overhead
* - Forces cache rotation when executed
*/
export function getMaintenanceWorkflow() {
return {
"1": {
"class_type": "EmptyImage",
"inputs": {
"width": 64, // Tiny 64x64 image
"height": 64, // Minimal VRAM usage
"batch_size": 1,
"color": 0 // Black image
}
},
"2": {
"class_type": "SaveImage",
"inputs": {
"images": ["1", 0],
"filename_prefix": "maintenance"
}
}
};
}
/**
* Alternative: Simple Noise Generation Workflow
* Uses latent space operations without loading heavy models
*/
export function getNoiseMaintenanceWorkflow() {
return {
"1": {
"class_type": "EmptyLatentImage",
"inputs": {
"width": 64,
"height": 64,
"batch_size": 1
}
},
"2": {
"class_type": "LatentUpscale",
"inputs": {
"samples": ["1", 0],
"upscale_method": "nearest-exact",
"width": 128,
"height": 128,
"crop": "disabled"
}
}
};
}
/**
* SD 1.5 Tiny Workflow
* Uses the much smaller SD 1.5 model (2GB) to force FLUX (11GB) out of cache
*/
export function getSD15MaintenanceWorkflow() {
return {
"1": {
"class_type": "CheckpointLoaderSimple",
"inputs": {
"ckpt_name": "v1-5-pruned-emaonly-fp16.safetensors" // 2GB model
}
},
"2": {
"class_type": "EmptyLatentImage",
"inputs": {
"width": 64,
"height": 64,
"batch_size": 1
}
},
"3": {
"class_type": "CLIPTextEncode",
"inputs": {
"text": "test",
"clip": ["1", 1]
}
},
"4": {
"class_type": "KSampler",
"inputs": {
"seed": 42,
"steps": 1, // Single step - fastest possible
"cfg": 1.0,
"sampler_name": "euler",
"scheduler": "simple",
"denoise": 0.1, // Minimal denoising
"model": ["1", 0],
"positive": ["3", 0],
"negative": ["3", 0],
"latent_image": ["2", 0]
}
},
"5": {
"class_type": "VAEDecode",
"inputs": {
"samples": ["4", 0],
"vae": ["1", 2]
}
},
"6": {
"class_type": "SaveImage",
"inputs": {
"images": ["5", 0],
"filename_prefix": "maintenance_sd15"
}
}
};
}
/**
* Execute maintenance workflow to free VRAM
* This should be called periodically or when VRAM usage is high
*/
export async function runMaintenanceWorkflow(comfyuiClient, strategy = 'sd15') {
console.log(`๐งน Running maintenance workflow (${strategy}) to free VRAM...`);
let workflow;
switch(strategy) {
case 'empty':
workflow = getMaintenanceWorkflow();
break;
case 'noise':
workflow = getNoiseMaintenanceWorkflow();
break;
case 'sd15':
workflow = getSD15MaintenanceWorkflow();
break;
default:
workflow = getMaintenanceWorkflow();
}
try {
const startTime = Date.now();
// Queue the lightweight workflow
const result = await comfyuiClient.queuePrompt(workflow);
// Wait for completion (should be very fast)
if (result.prompt_id) {
await comfyuiClient.waitForExecution(result.prompt_id);
}
const duration = Date.now() - startTime;
console.log(`โ
Maintenance workflow completed in ${duration}ms`);
// The LRU cache should now have evicted heavy models
return {
success: true,
duration,
strategy
};
} catch (error) {
console.error('โ Maintenance workflow failed:', error);
return {
success: false,
error: error.message,
strategy
};
}
}
/**
* Smart maintenance scheduler
* Runs maintenance based on various triggers
*/
export class MaintenanceScheduler {
constructor(comfyuiClient, options = {}) {
this.client = comfyuiClient;
this.config = {
idleTimeout: options.idleTimeout || 5 * 60 * 1000, // 5 minutes idle
periodicInterval: options.periodicInterval || 30 * 60 * 1000, // 30 minutes
strategy: options.strategy || 'sd15',
enabled: options.enabled !== false
};
this.lastActivity = Date.now();
this.isIdle = false;
this.intervalId = null;
if (this.config.enabled) {
this.start();
}
}
start() {
// Periodic maintenance
this.intervalId = setInterval(() => {
this.checkAndRunMaintenance();
}, this.config.periodicInterval);
console.log('๐ Maintenance scheduler started');
}
stop() {
if (this.intervalId) {
clearInterval(this.intervalId);
this.intervalId = null;
}
console.log('โน๏ธ Maintenance scheduler stopped');
}
updateActivity() {
this.lastActivity = Date.now();
this.isIdle = false;
}
async checkAndRunMaintenance() {
const idleTime = Date.now() - this.lastActivity;
// Only run if system has been idle
if (idleTime >= this.config.idleTimeout) {
console.log(`System idle for ${Math.round(idleTime/1000)}s, running maintenance...`);
await runMaintenanceWorkflow(this.client, this.config.strategy);
this.isIdle = true;
}
}
async forceMaintenance() {
console.log('Forcing immediate maintenance workflow...');
return await runMaintenanceWorkflow(this.client, this.config.strategy);
}
}
export default {
getMaintenanceWorkflow,
getNoiseMaintenanceWorkflow,
getSD15MaintenanceWorkflow,
runMaintenanceWorkflow,
MaintenanceScheduler
};