Packages
snakepit
0.7.2
0.13.0
0.12.0
0.11.1
0.11.0
0.10.1
0.10.0
0.9.1
0.9.0
0.8.9
0.8.8
0.8.7
0.8.6
0.8.5
0.8.4
0.8.3
0.8.2
0.8.1
0.8.0
0.7.7
0.7.6
0.7.5
0.7.4
0.7.3
0.7.2
0.7.1
0.7.0
0.6.11
0.6.10
0.6.9
0.6.8
0.6.7
0.6.6
0.6.5
0.6.4
0.6.3
0.6.2
0.6.1
0.6.0
0.5.1
0.5.0
0.4.3
0.4.2
0.4.1
0.4.0
0.3.3
0.3.2
0.3.1
0.3.0
0.2.1
0.2.0
0.1.2
0.1.1
0.1.0
High-performance pooler and session manager for external language integrations. Supports Python, Node.js, Ruby, and more with gRPC streaming, session management, and production-ready process cleanup.
Current section
Files
Jump to
Current section
Files
DIAGRAMS.md
# Snakepit Architecture Diagrams
> Visual reference for Snakepit v0.7.2 architecture
## System Overview
```mermaid
flowchart TB
subgraph BEAM["BEAM VM"]
subgraph Snakepit["Snakepit.Supervisor"]
SS[SessionStore]
TR[ToolRegistry]
GS[GRPC.Server]
Pool[Pool GenServer]
subgraph WS["WorkerSupervisor"]
W1[Worker.Starter 1]
W2[Worker.Starter 2]
WN[Worker.Starter N]
end
PR[ProcessRegistry]
TS[Telemetry.GrpcStream]
AC[ApplicationCleanup]
end
end
subgraph Python["Python Processes"]
P1[grpc_server.py :50001]
P2[grpc_server.py :50002]
PN[grpc_server.py :500NN]
end
W1 --> P1
W2 --> P2
WN --> PN
Pool --> WS
PR --> P1
PR --> P2
PR --> PN
P1 -.->|callbacks| GS
P2 -.->|callbacks| GS
PN -.->|callbacks| GS
P1 -.->|telemetry| TS
P2 -.->|telemetry| TS
PN -.->|telemetry| TS
```
## Supervision Tree
```mermaid
flowchart TD
S[Snakepit.Supervisor<br/>:one_for_one]
S --> SS[SessionStore<br/>GenServer + ETS]
S --> TR[ToolRegistry<br/>GenServer + ETS]
S --> GSS[GRPC.Server.Supervisor]
S --> GCS[GRPC.Client.Supervisor]
S --> REG[Pool.Registry<br/>ETS]
S --> PR[Pool.ProcessRegistry<br/>ETS + DETS]
S --> WSR[Worker.StarterRegistry<br/>ETS]
S --> TGS[Telemetry.GrpcStream<br/>GenServer]
S --> P[Pool<br/>GenServer]
S --> AC[ApplicationCleanup<br/>GenServer]
P --> WS[WorkerSupervisor<br/>DynamicSupervisor]
WS --> ST1[Worker.Starter 1<br/>Supervisor :permanent]
WS --> ST2[Worker.Starter 2<br/>Supervisor :permanent]
WS --> STN[Worker.Starter N<br/>Supervisor :permanent]
ST1 --> GW1[GRPCWorker 1<br/>GenServer :transient]
ST2 --> GW2[GRPCWorker 2<br/>GenServer :transient]
STN --> GWN[GRPCWorker N<br/>GenServer :transient]
style S fill:#4f46e5,color:#fff
style P fill:#6366f1,color:#fff
style WS fill:#8b5cf6,color:#fff
style ST1 fill:#a78bfa,color:#000
style ST2 fill:#a78bfa,color:#000
style STN fill:#a78bfa,color:#000
```
## Request Flow
```mermaid
sequenceDiagram
participant App as Application
participant Pool as Pool GenServer
participant WS as WorkerSupervisor
participant GW as GRPCWorker
participant Py as Python Process
App->>Pool: execute("cmd", args)
alt Worker Available
Pool->>Pool: Pop from :available set
Pool->>GW: execute(cmd, args)
GW->>Py: gRPC ExecuteTool
Py-->>GW: ToolResult
GW-->>Pool: {:ok, result}
Pool->>Pool: Return to :available set
Pool-->>App: {:ok, result}
else No Workers Available
Pool->>Pool: Enqueue request
Note over Pool: Wait for worker checkin
Pool->>GW: execute(cmd, args)
GW->>Py: gRPC ExecuteTool
Py-->>GW: ToolResult
GW-->>Pool: {:ok, result}
Pool-->>App: {:ok, result}
end
```
## Worker Startup Sequence
```mermaid
sequenceDiagram
participant Pool as Pool
participant WS as WorkerSupervisor
participant Starter as Worker.Starter
participant GW as GRPCWorker
participant Port as OS Port
participant Py as Python Process
Pool->>WS: start_worker(worker_id, config)
WS->>Starter: start_link(worker_id)
Starter->>GW: start_link(config)
GW->>Port: open_port({:spawn, "python3 grpc_server.py"})
Port->>Py: spawn process
Py->>Py: bind to ephemeral port
Py-->>Port: GRPC_READY:50001
Port-->>GW: {:data, "GRPC_READY:50001"}
GW->>Py: gRPC connect to :50001
GW->>Py: ping()
Py-->>GW: pong
GW->>Pool: register as available
Pool->>Pool: Add to :available set
```
## Session Affinity Flow
```mermaid
flowchart TD
A[execute_in_session<br/>session_id, cmd, args]
A --> B{Session exists?}
B -->|No| C[Create new session]
B -->|Yes| D[Get session]
C --> E{Any worker available?}
D --> F{last_worker_id<br/>available?}
F -->|Yes| G[Use preferred worker]
F -->|No| E
E -->|Yes| H[Pick any available worker]
E -->|No| I[Enqueue request]
G --> J[Execute command]
H --> J
I --> J
J --> K[Update session.last_worker_id]
K --> L[Return result]
```
## Streaming Flow
```mermaid
sequenceDiagram
participant App as Application
participant Pool as Pool
participant GW as GRPCWorker
participant Py as Python Worker
App->>Pool: execute_stream(cmd, args, callback)
Pool->>Pool: checkout_worker()
Pool-->>App: worker_pid
App->>GW: execute_stream(cmd, args, callback)
GW->>Py: ExecuteStreamingTool
loop Until is_final
Py-->>GW: ToolChunk{data, is_final: false}
GW->>App: callback.(chunk)
end
Py-->>GW: ToolChunk{data, is_final: true}
GW->>App: callback.(final_chunk)
GW-->>App: :ok
App->>Pool: checkin_worker(worker_pid)
Pool->>Pool: Return to :available set
```
## Telemetry Event Flow
```mermaid
flowchart LR
subgraph Python["Python Worker"]
PA[Adapter]
TE[telemetry.emit]
TS[TelemetryStream]
end
subgraph Elixir["Elixir"]
GS[GrpcStream]
NM[Naming]
SM[SafeMetadata]
TL[:telemetry]
OT[OpenTelemetry]
PM[Prometheus]
end
PA -->|event| TE
TE -->|gRPC stream| TS
TS -->|TelemetryEvent| GS
GS --> NM
NM -->|validate event| SM
SM -->|sanitize metadata| TL
TL --> OT
TL --> PM
```
## Worker Profiles
```mermaid
flowchart TB
subgraph Process["Process Profile (Default)"]
direction TB
PP[Pool]
PP --> PW1[Worker 1<br/>Python Process]
PP --> PW2[Worker 2<br/>Python Process]
PP --> PW3[Worker 3<br/>Python Process]
PW1 --> PT1[1 Thread]
PW2 --> PT2[1 Thread]
PW3 --> PT3[1 Thread]
end
subgraph Thread["Thread Profile (Python 3.13+)"]
direction TB
TP[Pool]
TP --> TW1[Worker 1<br/>Python Process]
TP --> TW2[Worker 2<br/>Python Process]
TW1 --> TT1[Thread 1]
TW1 --> TT2[Thread 2]
TW1 --> TT3[Thread 3]
TW1 --> TT4[Thread 4]
TW2 --> TT5[Thread 1]
TW2 --> TT6[Thread 2]
TW2 --> TT7[Thread 3]
TW2 --> TT8[Thread 4]
end
```
## Heartbeat Monitoring
```mermaid
sequenceDiagram
participant HM as HeartbeatMonitor
participant GW as GRPCWorker
participant Py as Python Process
loop Every heartbeat_interval
HM->>GW: send_heartbeat()
GW->>Py: Heartbeat request
alt Healthy
Py-->>GW: HeartbeatResponse{memory_mb, uptime}
GW-->>HM: {:ok, stats}
HM->>HM: Reset missed_count
else Timeout
Note over GW,Py: No response within timeout
HM->>HM: Increment missed_count
alt missed_count >= max_missed
HM->>GW: terminate (unhealthy)
Note over GW: Supervisor restarts worker
end
end
end
```
## Graceful Shutdown
```mermaid
sequenceDiagram
participant App as Application.stop
participant S as Supervisor
participant AC as ApplicationCleanup
participant Pool as Pool
participant WS as WorkerSupervisor
participant GW as GRPCWorker
participant Py as Python
App->>S: stop
S->>AC: terminate (last child)
par Terminate all workers
AC->>Pool: stop
Pool->>WS: stop
WS->>GW: terminate
GW->>Py: SIGTERM
alt Graceful exit
Py-->>GW: exit 0
else Force kill after timeout
GW->>Py: SIGKILL
end
end
AC->>AC: Verify no orphans
AC-->>S: :ok
```
## Error Recovery
```mermaid
flowchart TD
E[Worker Error]
E --> T{Error Type}
T -->|Python crash| A[GRPCWorker receives :DOWN]
T -->|gRPC failure| B[Connection lost]
T -->|Timeout| C[Request timeout]
A --> D[Worker.Starter detects child exit]
B --> D
D --> F{Exit reason}
F -->|:normal| G[No restart]
F -->|abnormal| H[Starter restarts GRPCWorker]
H --> I[New Python process spawned]
I --> J[gRPC connection established]
J --> K[Worker re-registered as available]
C --> L[Request returned with error]
L --> M[Worker returned to available<br/>if still healthy]
```
## Configuration Merge
```mermaid
flowchart TD
A[Application Config]
B[Pool-specific Config]
C[Adapter Defaults]
D[Environment Variables]
A --> E[Config.normalize]
B --> E
C --> E
D --> E
E --> F{Simple or Multi-pool?}
F -->|Simple| G[Convert to single-pool list]
F -->|Multi-pool| H[Use pools list as-is]
G --> I[Validated Config]
H --> I
I --> J[Pool GenServer]
I --> K[GRPCWorker]
I --> L[Python Environment]
```
**Note**: Simple format (`pool_size: N, adapter_module: X`) is auto-converted to multi-pool format for internal use. Both formats are fully supported.
## Component Summary
| Component | Type | Purpose |
|-----------|------|---------|
| Snakepit.Supervisor | Supervisor | Top-level OTP supervision |
| Pool | GenServer | Request distribution, worker tracking |
| WorkerSupervisor | DynamicSupervisor | Dynamic worker management |
| Worker.Starter | Supervisor | Per-worker crash isolation |
| GRPCWorker | GenServer | Python process + gRPC connection |
| SessionStore | GenServer + ETS | Session management with TTL |
| ToolRegistry | GenServer + ETS | Bidirectional tool registration |
| ProcessRegistry | GenServer + ETS/DETS | External PID tracking |
| Telemetry.GrpcStream | GenServer | Python telemetry folding |
| ApplicationCleanup | GenServer | Shutdown guarantees |