@sethdouglasford/claude-flow
Version:
Claude Code Flow - Advanced AI-powered development workflows with SPARC methodology
159 lines • 5.83 kB
JavaScript
/**
* Work stealing algorithm for load balancing between agents
*/
/**
* Work stealing coordinator for load balancing
*/
export class WorkStealingCoordinator {
config;
eventBus;
logger;
workloads = new Map();
stealInterval;
taskDurations = new Map(); // agentId -> task durations
constructor(config, eventBus, logger) {
this.config = config;
this.eventBus = eventBus;
this.logger = logger;
}
initialize() {
if (!this.config.enabled) {
this.logger.info("Work stealing is disabled");
return;
}
this.logger.info("Initializing work stealing coordinator");
// Start periodic steal checks
this.stealInterval = setInterval(() => this.checkAndSteal(), this.config.stealInterval);
}
shutdown() {
if (this.stealInterval) {
clearInterval(this.stealInterval);
}
this.workloads.clear();
this.taskDurations.clear();
}
updateAgentWorkload(agentId, workload) {
const existing = this.workloads.get(agentId) ?? {
agentId,
taskCount: 0,
avgTaskDuration: 0,
cpuUsage: 0,
memoryUsage: 0,
priority: 0,
capabilities: [],
};
this.workloads.set(agentId, { ...existing, ...workload });
}
recordTaskDuration(agentId, duration) {
let durations = this.taskDurations.get(agentId);
if (!durations) {
durations = [];
this.taskDurations.set(agentId, durations);
}
durations.push(duration);
// Keep only last 100 durations
if (durations.length > 100) {
durations.shift();
}
// Update average duration
const avg = durations.reduce((sum, d) => sum + d, 0) / durations.length;
this.updateAgentWorkload(agentId, { avgTaskDuration: avg });
}
checkAndSteal() {
const workloads = Array.from(this.workloads.values());
if (workloads.length < 2) {
return; // Need at least 2 agents
}
// Sort by task count (ascending)
workloads.sort((a, b) => a.taskCount - b.taskCount);
const minLoaded = workloads[0];
const maxLoaded = workloads[workloads.length - 1];
// Check if stealing is warranted
const difference = maxLoaded.taskCount - minLoaded.taskCount;
if (difference < this.config.stealThreshold) {
return; // Not enough imbalance
}
// Calculate how many tasks to steal
const tasksToSteal = Math.min(Math.floor(difference / 2), this.config.maxStealBatch);
this.logger.info("Initiating work stealing", {
from: maxLoaded.agentId,
to: minLoaded.agentId,
tasksToSteal,
difference,
});
// Emit steal request event
this.eventBus.emit("workstealing:request", {
sourceAgent: maxLoaded.agentId,
targetAgent: minLoaded.agentId,
taskCount: tasksToSteal,
});
}
/**
* Find the best agent for a task based on capabilities and load
*/
findBestAgent(task, agents) {
const candidates = [];
for (const agent of agents) {
const workload = this.workloads.get(agent.id);
if (!workload) {
continue;
}
// Calculate score based on multiple factors
let score = 100;
// Factor 1: Task count (lower is better)
score -= workload.taskCount * 10;
// Factor 2: CPU usage (lower is better)
score -= workload.cpuUsage * 0.5;
// Factor 3: Memory usage (lower is better)
score -= workload.memoryUsage * 0.3;
// Factor 4: Agent priority (higher is better)
score += agent.priority * 5;
// Factor 5: Capability match
const taskType = task.type;
if (agent.capabilities.includes(taskType)) {
score += 20; // Bonus for capability match
}
// Factor 6: Average task duration (predictive load)
const predictedLoad = workload.avgTaskDuration * workload.taskCount;
score -= predictedLoad / 1000; // Convert to seconds
candidates.push({ agentId: agent.id, score });
}
if (candidates.length === 0) {
return null;
}
// Sort by score (descending) and return best
candidates.sort((a, b) => b.score - a.score);
this.logger.debug("Agent selection scores", {
taskId: task.id,
candidates: candidates.slice(0, 5), // Top 5
});
return candidates[0].agentId;
}
getWorkloadStats() {
const stats = {
totalAgents: this.workloads.size,
workloads: {},
};
let totalTasks = 0;
let minTasks = Infinity;
let maxTasks = 0;
for (const [agentId, workload] of this.workloads) {
totalTasks += workload.taskCount;
minTasks = Math.min(minTasks, workload.taskCount);
maxTasks = Math.max(maxTasks, workload.taskCount);
stats.workloads[agentId] = {
taskCount: workload.taskCount,
avgTaskDuration: workload.avgTaskDuration,
cpuUsage: workload.cpuUsage,
memoryUsage: workload.memoryUsage,
};
}
stats.totalTasks = totalTasks;
stats.avgTasksPerAgent = totalTasks / this.workloads.size;
stats.minTasks = minTasks === Infinity ? 0 : minTasks;
stats.maxTasks = maxTasks;
stats.imbalance = maxTasks - (minTasks === Infinity ? 0 : minTasks);
return stats;
}
}
//# sourceMappingURL=work-stealing.js.map