Packages
snakepit
0.3.1
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
README_BRIDGES.md
# Snakepit Python Bridges Documentation
## Overview
Snakepit provides multiple Python bridge implementations to enable communication between Elixir and Python processes. Each bridge version offers different capabilities and trade-offs, allowing you to choose the best fit for your use case.
## Bridge Versions
### 1. V1 Generic Bridge (Deprecated)
**File**: `priv/python/generic_bridge.py`
**Status**: Deprecated - Use V2 for new projects
The original bridge implementation that established the core protocol:
- Simple stdin/stdout communication
- 4-byte length header + JSON payload protocol
- Basic command handler pattern
- Built-in error handling and graceful shutdown
**Features**:
- Minimal dependencies (only Python stdlib)
- Extensible via `BaseCommandHandler` class
- Built-in commands: ping, echo, compute, info
- Signal handling for clean shutdown
**Example Usage**:
```python
class MyCustomHandler(BaseCommandHandler):
def _register_commands(self):
self.register_command("my_command", self.handle_my_command)
def handle_my_command(self, args):
return {"result": "processed", "input": args}
handler = ProtocolHandler(MyCustomHandler())
handler.run()
```
### 2. V2 Generic Bridge (Current)
**File**: `priv/python/generic_bridge_v2.py`
**Status**: Active - Recommended for production
A complete rewrite with proper package structure and enhanced features:
- Uses the `snakepit_bridge` package for modularity
- Support for multiple wire protocols (JSON, MessagePack, auto-detection)
- Better error handling and broken pipe suppression
- Production-ready architecture
**Key Improvements**:
- Modular package structure (`snakepit_bridge/*`)
- Protocol abstraction (JSON/MessagePack)
- Cleaner separation of concerns
- Better testing support
- Command-line options for configuration
**Usage**:
```bash
python generic_bridge_v2.py --mode pool-worker --protocol msgpack --quiet
```
**Package Structure**:
```
snakepit_bridge/
├── __init__.py # Package exports
├── core.py # Core protocol handling
├── adapters/ # Command handler implementations
│ ├── generic.py # Default generic handler
│ └── grpc_streaming.py # gRPC streaming adapter
└── cli/ # CLI entry points
```
### 3. Enhanced Bridge (DSPy/ML Focused)
**File**: `priv/python/enhanced_bridge.py`
**Status**: Active - Used by DSPex
Built on V2 architecture with dynamic method invocation capabilities:
- Universal Python method calls via dynamic invocation
- Object persistence and lifecycle management
- Framework plugin system for optimized integrations
- Smart serialization with type awareness
- Backward compatibility with V2 commands
**Key Features**:
- **Dynamic Method Invocation**: Call any Python method/class dynamically
- **Object Storage**: Store and retrieve Python objects between calls
- **Framework Plugins**: Optimized support for DSPy, Transformers, Pandas
- **Pipeline Support**: Execute sequences of operations
- **Inspection**: Introspect objects and their capabilities
**Command Set**:
```elixir
# Dynamic calls
{:ok, result} = Python.call(pid, "dspy.Predict", %{signature: "question -> answer"})
{:ok, result} = Python.call(pid, "stored.my_obj.forward", %{input: "test"})
# Storage management
{:ok, _} = Python.store(pid, "my_model", model)
{:ok, model} = Python.retrieve(pid, "my_model")
# Pipeline execution
{:ok, results} = Python.pipeline(pid, [
%{target: "dspy.configure", kwargs: %{lm: "gemini"}},
%{target: "dspy.Predict", kwargs: %{signature: sig}, store_as: "predictor"},
%{target: "stored.predictor.forward", kwargs: inputs}
])
```
**Framework Plugins**:
1. **DSPyPlugin**:
- Special handling for Prediction objects
- Gemini configuration support
- Automatic attribute extraction
2. **TransformersPlugin**:
- Pipeline serialization
- Model information extraction
3. **PandasPlugin**:
- DataFrame/Series serialization
- Shape and dtype information
### 4. gRPC Bridge (Streaming/High-Performance)
**File**: `priv/python/grpc_bridge.py`
**Status**: Experimental - For streaming use cases
Modern gRPC-based bridge for advanced features:
- True bidirectional streaming
- Multiplexing support
- Session management
- Binary data handling
- Health checks and monitoring
**Features**:
- Replaces stdin/stdout with gRPC protocol
- Supports streaming responses
- Better performance for high-throughput scenarios
- Session-based execution
- Worker statistics and monitoring
**Protocol**:
```protobuf
service SnakepitBridge {
rpc Execute(ExecuteRequest) returns (ExecuteResponse);
rpc ExecuteStream(ExecuteRequest) returns (stream StreamResponse);
rpc ExecuteInSession(SessionRequest) returns (ExecuteResponse);
rpc ExecuteInSessionStream(SessionRequest) returns (stream StreamResponse);
rpc Health(HealthRequest) returns (HealthResponse);
rpc GetInfo(InfoRequest) returns (InfoResponse);
}
```
**Usage**:
```bash
# Start gRPC server
python grpc_bridge.py --port 50051
# With custom adapter
python grpc_bridge.py --port 50051 --adapter my_module.MyAdapter
```
## Bridge Selection Guide
### Use V2 Generic Bridge when:
- You need a stable, production-ready solution
- Your use case involves simple request/response patterns
- You want minimal dependencies
- You're building custom adapters
### Use Enhanced Bridge when:
- Working with ML frameworks (DSPy, Transformers, etc.)
- You need dynamic method invocation
- Object persistence between calls is required
- Building complex ML pipelines
- Integrating with DSPex
### Use gRPC Bridge when:
- Streaming responses are required
- High-throughput communication is needed
- Session management is important
- You need better monitoring/observability
### Avoid V1 Bridge:
- Deprecated and will be removed
- V2 provides all features with better architecture
## Creating Custom Adapters
All bridges support custom adapters by extending `BaseCommandHandler`:
```python
from snakepit_bridge import BaseCommandHandler, ProtocolHandler
class MyMLHandler(BaseCommandHandler):
def _register_commands(self):
self.register_command("train", self.handle_train)
self.register_command("predict", self.handle_predict)
def handle_train(self, args):
# Training logic here
return {"status": "trained", "metrics": {...}}
def handle_predict(self, args):
# Prediction logic here
return {"predictions": [...]}
# Use with any bridge version
handler = ProtocolHandler(MyMLHandler())
handler.run()
```
## Wire Protocol
All bridges (except gRPC) use the same wire protocol:
1. **Length Header**: 4 bytes, big-endian, indicating payload size
2. **Payload**: JSON or MessagePack encoded data
**Request Format**:
```json
{
"id": "unique-request-id",
"command": "command_name",
"args": {
"param1": "value1",
"param2": "value2"
}
}
```
**Response Format**:
```json
{
"id": "unique-request-id",
"success": true,
"result": {
"data": "response data"
},
"timestamp": "2024-01-01T00:00:00Z"
}
```
## Performance Considerations
1. **JSON vs MessagePack**: MessagePack is ~2-3x faster for large payloads
2. **Object Storage**: Enhanced bridge keeps objects in memory, avoiding serialization overhead
3. **gRPC Streaming**: Best for real-time data or large responses
4. **Pool Size**: Configure based on workload (default: 4 workers)
## Error Handling
All bridges implement robust error handling:
- Graceful shutdown on SIGTERM/SIGINT
- Broken pipe detection and suppression
- Timeout support (configured in Snakepit)
- Detailed error messages with stack traces
## Migration Guide
### From V1 to V2:
1. Update import: Use `snakepit_bridge` package
2. Change startup: Use `generic_bridge_v2.py`
3. Commands remain compatible
### From Generic to Enhanced:
1. Replace bridge script with `enhanced_bridge.py`
2. Existing commands work unchanged
3. New dynamic features available immediately
### To gRPC:
1. Install gRPC dependencies: `pip install grpcio`
2. Generate protobuf files: `make proto-python`
3. Update Snakepit configuration for gRPC mode
4. Implement streaming in your adapter if needed
## Best Practices
1. **Choose the Right Bridge**: Match bridge capabilities to your needs
2. **Handle Errors Gracefully**: Always wrap calls in try/except
3. **Manage Object Lifecycle**: Clean up stored objects when done
4. **Monitor Performance**: Use built-in metrics (uptime, request count)
5. **Test Thoroughly**: Each bridge has different edge cases
6. **Version Dependencies**: Pin Python package versions for stability
## Troubleshooting
### Common Issues:
1. **ImportError**: Bridge package not in Python path
- Solution: Ensure `snakepit_bridge` directory is accessible
2. **Broken Pipe Errors**: Elixir process terminated
- Solution: Bridges handle this automatically, check Elixir logs
3. **Serialization Errors**: Complex objects can't be JSON encoded
- Solution: Use Enhanced bridge with smart serialization
4. **Performance Issues**: Slow response times
- Solution: Switch to MessagePack or gRPC, increase pool size
5. **Memory Growth**: Stored objects not cleaned up
- Solution: Call `clear_session` or `delete_stored` periodically
## Future Roadmap
1. **Arrow Support**: Apache Arrow for zero-copy data transfer
2. **Async Support**: asyncio integration for better concurrency
3. **Distributed Mode**: Multi-node Python worker support
4. **GPU Support**: CUDA-aware serialization
5. **Monitoring**: OpenTelemetry integration