-
Notifications
You must be signed in to change notification settings - Fork 3.1k
Description
Summary
When running workflows with loops containing agent blocks that make many tool calls (e.g., MCP file operations), memory accumulates unbounded until system OOM. This caused my 64GB system to run out of memory during workflow execution.
Environment
- Self-hosted via Docker
- macOS with 64GB RAM
- Docker containers with no memory limits (default)
Root Cause Analysis
After investigating the codebase, I identified 6 critical memory accumulation points with no bounds:
1. allIterationOutputs in LoopScope (CRITICAL)
File: apps/sim/executor/orchestrators/loop.ts (line 144)
if (iterationResults.length > 0) {
scope.allIterationOutputs.push(iterationResults) // UNBOUNDED
}Every loop iteration pushes results to this array with no size limit or pruning.
2. blockLogs array in ExecutionContext (CRITICAL)
File: apps/sim/executor/execution/block-executor.ts (lines 60-62)
blockLog = this.createBlockLog(ctx, node.id, block, node)
ctx.blockLogs.push(blockLog) // UNBOUNDED - every block execution addsEvery block execution (including each loop iteration) pushes to this array.
3. TraceSpans accumulation
File: apps/sim/lib/logs/execution/trace-spans/trace-spans.ts
The buildTraceSpans() function creates spans for ALL block logs and tool calls, building an unbounded in-memory tree structure.
4. Tool calls array per agent
File: apps/sim/executor/handlers/agent/agent-handler.ts (lines 250-318)
Each agent execution stores all tool calls in span.toolCalls array. With 100 tool calls per agent × 1000 iterations = 100,000 ToolCall objects.
5. File extraction unbounded recursion
File: apps/sim/lib/logs/execution/logger.ts (lines 621-695)
extractFilesFromExecution() recursively walks the entire trace span tree with no depth limits.
6. Memory table JSONB concatenation
File: apps/sim/executor/handlers/agent/memory.ts (line ~580)
data: sql`${memory.data} || ${JSON.stringify([message])}::jsonb` // Unbounded appendMemory Growth Calculation
For a workflow with:
- Loop: 1000 iterations
- Agent block per iteration with 100 tool calls (file read/write via MCP)
Memory consumption:
blockLogs: 1000 entries × 50KB = 50MBallIterationOutputs: 1000 × 1MB = 1GB- Tool calls in spans: 100,000 objects = 1GB
- TraceSpans tree traversal: O(GB) object graph
- Total: 2-10+ GB in memory, persisted to
executionDataJSONB
Reproduction Steps
- Create a workflow with a Loop block (while condition)
- Inside loop: StateTracker function → Agent with MCP tools (file read/write) → Reviewer
- Run the workflow with multiple tasks that require many file operations
- Monitor Docker container memory with
docker stats - Observe memory climbing until OOM
Suggested Fixes
Short-term mitigations:
- Add iteration limits check with memory awareness:
const MAX_MEMORY_PER_LOOP = 100 * 1024 * 1024; // 100MB
if (estimateSize(scope.allIterationOutputs) > MAX_MEMORY_PER_LOOP) {
logger.warn('Loop memory limit reached, truncating older iterations');
scope.allIterationOutputs = scope.allIterationOutputs.slice(-10);
}- Stream block logs to database instead of accumulating:
// Instead of ctx.blockLogs.push(blockLog)
await this.persistBlockLog(blockLog);- Truncate tool call results in spans:
const MAX_TOOL_RESULT_SIZE = 10000;
toolCall.result = truncate(toolCall.result, MAX_TOOL_RESULT_SIZE);Long-term solutions:
- Implement streaming execution logs (write to DB incrementally)
- Add configurable memory limits per execution
- Implement log rotation/pruning during long-running executions
- Add memory pressure monitoring with graceful degradation
Workaround
Set Docker memory limits to prevent system-wide OOM:
# docker-compose.override.yml
services:
simstudio-app:
deploy:
resources:
limits:
memory: 8GRelated Files
apps/sim/executor/orchestrators/loop.tsapps/sim/executor/execution/block-executor.tsapps/sim/lib/logs/execution/trace-spans/trace-spans.tsapps/sim/lib/logs/execution/logger.tsapps/sim/executor/handlers/agent/agent-handler.tsapps/sim/executor/handlers/agent/memory.tspackages/db/schema.ts(executionData JSONB field)