simple_acp 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.envrc +1 -0
- data/CHANGELOG.md +5 -0
- data/COMMITS.md +196 -0
- data/LICENSE.txt +21 -0
- data/README.md +385 -0
- data/Rakefile +13 -0
- data/docs/api/client-base.md +383 -0
- data/docs/api/index.md +159 -0
- data/docs/api/models.md +286 -0
- data/docs/api/server-base.md +379 -0
- data/docs/api/storage.md +347 -0
- data/docs/assets/images/simple_acp.jpg +0 -0
- data/docs/client/index.md +279 -0
- data/docs/client/sessions.md +324 -0
- data/docs/client/streaming.md +345 -0
- data/docs/client/sync-async.md +308 -0
- data/docs/core-concepts/agents.md +253 -0
- data/docs/core-concepts/events.md +337 -0
- data/docs/core-concepts/index.md +147 -0
- data/docs/core-concepts/messages.md +211 -0
- data/docs/core-concepts/runs.md +278 -0
- data/docs/core-concepts/sessions.md +281 -0
- data/docs/examples.md +659 -0
- data/docs/getting-started/configuration.md +166 -0
- data/docs/getting-started/index.md +62 -0
- data/docs/getting-started/installation.md +95 -0
- data/docs/getting-started/quick-start.md +189 -0
- data/docs/index.md +119 -0
- data/docs/server/creating-agents.md +360 -0
- data/docs/server/http-endpoints.md +411 -0
- data/docs/server/index.md +218 -0
- data/docs/server/multi-turn.md +329 -0
- data/docs/server/streaming.md +315 -0
- data/docs/storage/custom.md +414 -0
- data/docs/storage/index.md +176 -0
- data/docs/storage/memory.md +198 -0
- data/docs/storage/postgresql.md +350 -0
- data/docs/storage/redis.md +287 -0
- data/examples/01_basic/client.rb +88 -0
- data/examples/01_basic/server.rb +100 -0
- data/examples/02_async_execution/client.rb +107 -0
- data/examples/02_async_execution/server.rb +56 -0
- data/examples/03_run_management/client.rb +115 -0
- data/examples/03_run_management/server.rb +84 -0
- data/examples/04_rich_messages/client.rb +160 -0
- data/examples/04_rich_messages/server.rb +180 -0
- data/examples/05_await_resume/client.rb +164 -0
- data/examples/05_await_resume/server.rb +114 -0
- data/examples/06_agent_metadata/client.rb +188 -0
- data/examples/06_agent_metadata/server.rb +192 -0
- data/examples/README.md +252 -0
- data/examples/run_demo.sh +137 -0
- data/lib/simple_acp/client/base.rb +448 -0
- data/lib/simple_acp/client/sse.rb +141 -0
- data/lib/simple_acp/models/agent_manifest.rb +129 -0
- data/lib/simple_acp/models/await.rb +123 -0
- data/lib/simple_acp/models/base.rb +147 -0
- data/lib/simple_acp/models/errors.rb +102 -0
- data/lib/simple_acp/models/events.rb +256 -0
- data/lib/simple_acp/models/message.rb +235 -0
- data/lib/simple_acp/models/message_part.rb +225 -0
- data/lib/simple_acp/models/metadata.rb +161 -0
- data/lib/simple_acp/models/run.rb +298 -0
- data/lib/simple_acp/models/session.rb +137 -0
- data/lib/simple_acp/models/types.rb +210 -0
- data/lib/simple_acp/server/agent.rb +116 -0
- data/lib/simple_acp/server/app.rb +264 -0
- data/lib/simple_acp/server/base.rb +510 -0
- data/lib/simple_acp/server/context.rb +210 -0
- data/lib/simple_acp/server/falcon_runner.rb +61 -0
- data/lib/simple_acp/storage/base.rb +129 -0
- data/lib/simple_acp/storage/memory.rb +108 -0
- data/lib/simple_acp/storage/postgresql.rb +233 -0
- data/lib/simple_acp/storage/redis.rb +178 -0
- data/lib/simple_acp/version.rb +5 -0
- data/lib/simple_acp.rb +91 -0
- data/mkdocs.yml +152 -0
- data/sig/simple_acp.rbs +4 -0
- metadata +418 -0
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
# Memory Storage
|
|
2
|
+
|
|
3
|
+
The Memory storage backend stores all data in-process using thread-safe data structures. It's the default backend and ideal for development and testing.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Zero dependencies** - No external services required
|
|
8
|
+
- **Thread-safe** - Uses `concurrent-ruby` for safe concurrent access
|
|
9
|
+
- **Fast** - All operations are in-memory
|
|
10
|
+
- **Simple** - No configuration needed
|
|
11
|
+
|
|
12
|
+
## Limitations
|
|
13
|
+
|
|
14
|
+
- **Not persistent** - Data is lost when the process exits
|
|
15
|
+
- **Single process** - Cannot share data between processes
|
|
16
|
+
- **Memory bound** - Limited by available RAM
|
|
17
|
+
|
|
18
|
+
## Usage
|
|
19
|
+
|
|
20
|
+
### Basic Setup
|
|
21
|
+
|
|
22
|
+
```ruby
|
|
23
|
+
require 'simple_acp'
|
|
24
|
+
|
|
25
|
+
# Memory is the default
|
|
26
|
+
server = SimpleAcp::Server::Base.new
|
|
27
|
+
|
|
28
|
+
# Or explicitly
|
|
29
|
+
storage = SimpleAcp::Storage::Memory.new
|
|
30
|
+
server = SimpleAcp::Server::Base.new(storage: storage)
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### With Options
|
|
34
|
+
|
|
35
|
+
```ruby
|
|
36
|
+
storage = SimpleAcp::Storage::Memory.new(
|
|
37
|
+
# Currently no specific options
|
|
38
|
+
)
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Operations
|
|
42
|
+
|
|
43
|
+
### Runs
|
|
44
|
+
|
|
45
|
+
```ruby
|
|
46
|
+
# Save a run
|
|
47
|
+
storage.save_run(run)
|
|
48
|
+
|
|
49
|
+
# Get a run
|
|
50
|
+
run = storage.get_run("run-id")
|
|
51
|
+
|
|
52
|
+
# Delete a run
|
|
53
|
+
storage.delete_run("run-id")
|
|
54
|
+
|
|
55
|
+
# List runs
|
|
56
|
+
result = storage.list_runs(
|
|
57
|
+
agent_name: "echo", # Optional filter
|
|
58
|
+
session_id: "sess-1", # Optional filter
|
|
59
|
+
limit: 10,
|
|
60
|
+
offset: 0
|
|
61
|
+
)
|
|
62
|
+
puts result[:runs] # Array of runs
|
|
63
|
+
puts result[:total] # Total count
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Sessions
|
|
67
|
+
|
|
68
|
+
```ruby
|
|
69
|
+
# Save a session
|
|
70
|
+
storage.save_session(session)
|
|
71
|
+
|
|
72
|
+
# Get a session
|
|
73
|
+
session = storage.get_session("session-id")
|
|
74
|
+
|
|
75
|
+
# Delete a session
|
|
76
|
+
storage.delete_session("session-id")
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Events
|
|
80
|
+
|
|
81
|
+
```ruby
|
|
82
|
+
# Add an event
|
|
83
|
+
storage.add_event("run-id", event)
|
|
84
|
+
|
|
85
|
+
# Get events
|
|
86
|
+
events = storage.get_events("run-id", limit: 100, offset: 0)
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Utility Methods
|
|
90
|
+
|
|
91
|
+
### Clear All Data
|
|
92
|
+
|
|
93
|
+
```ruby
|
|
94
|
+
storage.clear!
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Get Statistics
|
|
98
|
+
|
|
99
|
+
```ruby
|
|
100
|
+
stats = storage.stats
|
|
101
|
+
|
|
102
|
+
puts "Runs: #{stats[:runs]}"
|
|
103
|
+
puts "Sessions: #{stats[:sessions]}"
|
|
104
|
+
puts "Events: #{stats[:events]}"
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Health Check
|
|
108
|
+
|
|
109
|
+
```ruby
|
|
110
|
+
if storage.ping
|
|
111
|
+
puts "Storage is healthy"
|
|
112
|
+
end
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Thread Safety
|
|
116
|
+
|
|
117
|
+
Memory storage uses `Concurrent::Map` from concurrent-ruby:
|
|
118
|
+
|
|
119
|
+
```ruby
|
|
120
|
+
# Safe for concurrent access
|
|
121
|
+
threads = 10.times.map do |i|
|
|
122
|
+
Thread.new do
|
|
123
|
+
run = create_run(i)
|
|
124
|
+
storage.save_run(run)
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
threads.each(&:join)
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Testing
|
|
132
|
+
|
|
133
|
+
Memory storage is ideal for tests:
|
|
134
|
+
|
|
135
|
+
```ruby
|
|
136
|
+
class MyAgentTest < Minitest::Test
|
|
137
|
+
def setup
|
|
138
|
+
@storage = SimpleAcp::Storage::Memory.new
|
|
139
|
+
@server = SimpleAcp::Server::Base.new(storage: @storage)
|
|
140
|
+
register_agents(@server)
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def teardown
|
|
144
|
+
@storage.clear!
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def test_agent_behavior
|
|
148
|
+
run = @server.run_sync(
|
|
149
|
+
agent_name: "echo",
|
|
150
|
+
input: [SimpleAcp::Models::Message.user("test")]
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
assert_equal "completed", run.status
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Migration to Production
|
|
159
|
+
|
|
160
|
+
When moving to production, switch to Redis or PostgreSQL:
|
|
161
|
+
|
|
162
|
+
```ruby
|
|
163
|
+
# Development
|
|
164
|
+
if ENV['RACK_ENV'] == 'development'
|
|
165
|
+
storage = SimpleAcp::Storage::Memory.new
|
|
166
|
+
else
|
|
167
|
+
# Production
|
|
168
|
+
storage = SimpleAcp::Storage::Redis.new(url: ENV['REDIS_URL'])
|
|
169
|
+
# or
|
|
170
|
+
storage = SimpleAcp::Storage::PostgreSQL.new(url: ENV['DATABASE_URL'])
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
server = SimpleAcp::Server::Base.new(storage: storage)
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## Best Practices
|
|
177
|
+
|
|
178
|
+
1. **Use for development** - Quick iteration without setup
|
|
179
|
+
2. **Use for tests** - Isolated, fast test runs
|
|
180
|
+
3. **Clear between tests** - Use `clear!` in teardown
|
|
181
|
+
4. **Monitor memory** - Watch for growing data in long runs
|
|
182
|
+
5. **Don't use in production** - Data loss on restart
|
|
183
|
+
|
|
184
|
+
## Implementation Details
|
|
185
|
+
|
|
186
|
+
The Memory backend uses these data structures:
|
|
187
|
+
|
|
188
|
+
| Data | Structure | Thread Safety |
|
|
189
|
+
|------|-----------|---------------|
|
|
190
|
+
| Runs | `Concurrent::Map` | Yes |
|
|
191
|
+
| Sessions | `Concurrent::Map` | Yes |
|
|
192
|
+
| Events | `Concurrent::Map` with `Mutex` | Yes |
|
|
193
|
+
|
|
194
|
+
## Next Steps
|
|
195
|
+
|
|
196
|
+
- Learn about [Redis](redis.md) for distributed deployments
|
|
197
|
+
- Explore [PostgreSQL](postgresql.md) for persistent storage
|
|
198
|
+
- Build a [Custom Backend](custom.md) for special needs
|
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
# PostgreSQL Storage
|
|
2
|
+
|
|
3
|
+
PostgreSQL storage provides permanent, relational storage ideal for production deployments requiring audit trails and complex queries.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Persistent** - Data survives restarts
|
|
8
|
+
- **ACID compliant** - Reliable transactions
|
|
9
|
+
- **Queryable** - Full SQL capabilities
|
|
10
|
+
- **Scalable** - Supports read replicas
|
|
11
|
+
|
|
12
|
+
## Requirements
|
|
13
|
+
|
|
14
|
+
Add the Sequel and pg gems to your Gemfile:
|
|
15
|
+
|
|
16
|
+
```ruby
|
|
17
|
+
gem 'sequel', '~> 5.0'
|
|
18
|
+
gem 'pg', '~> 1.5'
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Usage
|
|
22
|
+
|
|
23
|
+
### Basic Setup
|
|
24
|
+
|
|
25
|
+
```ruby
|
|
26
|
+
require 'simple_acp'
|
|
27
|
+
require 'simple_acp/storage/postgresql'
|
|
28
|
+
|
|
29
|
+
storage = SimpleAcp::Storage::PostgreSQL.new(
|
|
30
|
+
url: "postgres://localhost/simple_acp"
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
server = SimpleAcp::Server::Base.new(storage: storage)
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Configuration Options
|
|
37
|
+
|
|
38
|
+
```ruby
|
|
39
|
+
storage = SimpleAcp::Storage::PostgreSQL.new(
|
|
40
|
+
# Connection URL
|
|
41
|
+
url: "postgres://user:pass@host:5432/database",
|
|
42
|
+
|
|
43
|
+
# Or specify individually
|
|
44
|
+
host: "localhost",
|
|
45
|
+
port: 5432,
|
|
46
|
+
database: "simple_acp",
|
|
47
|
+
user: "postgres",
|
|
48
|
+
password: "secret",
|
|
49
|
+
|
|
50
|
+
# Or use existing Sequel connection
|
|
51
|
+
db: existing_sequel_db,
|
|
52
|
+
|
|
53
|
+
# Behavior
|
|
54
|
+
skip_setup: false # Skip automatic table creation
|
|
55
|
+
)
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Environment Variables
|
|
59
|
+
|
|
60
|
+
```ruby
|
|
61
|
+
# Uses DATABASE_URL if not specified
|
|
62
|
+
storage = SimpleAcp::Storage::PostgreSQL.new
|
|
63
|
+
|
|
64
|
+
# Reads from:
|
|
65
|
+
# ENV['DATABASE_URL'] || "postgres://localhost/acp"
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Database Schema
|
|
69
|
+
|
|
70
|
+
Tables are automatically created on first use:
|
|
71
|
+
|
|
72
|
+
### acp_runs
|
|
73
|
+
|
|
74
|
+
```sql
|
|
75
|
+
CREATE TABLE acp_runs (
|
|
76
|
+
run_id VARCHAR PRIMARY KEY,
|
|
77
|
+
agent_name VARCHAR NOT NULL,
|
|
78
|
+
session_id VARCHAR,
|
|
79
|
+
status VARCHAR NOT NULL,
|
|
80
|
+
output TEXT, -- JSON
|
|
81
|
+
error TEXT, -- JSON
|
|
82
|
+
await_request TEXT, -- JSON
|
|
83
|
+
created_at TIMESTAMP,
|
|
84
|
+
finished_at TIMESTAMP,
|
|
85
|
+
updated_at TIMESTAMP
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
CREATE INDEX idx_runs_agent ON acp_runs(agent_name);
|
|
89
|
+
CREATE INDEX idx_runs_session ON acp_runs(session_id);
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### acp_sessions
|
|
93
|
+
|
|
94
|
+
```sql
|
|
95
|
+
CREATE TABLE acp_sessions (
|
|
96
|
+
id VARCHAR PRIMARY KEY,
|
|
97
|
+
history TEXT, -- JSON
|
|
98
|
+
state TEXT, -- JSON
|
|
99
|
+
created_at TIMESTAMP,
|
|
100
|
+
updated_at TIMESTAMP
|
|
101
|
+
);
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### acp_events
|
|
105
|
+
|
|
106
|
+
```sql
|
|
107
|
+
CREATE TABLE acp_events (
|
|
108
|
+
id SERIAL PRIMARY KEY,
|
|
109
|
+
run_id VARCHAR NOT NULL,
|
|
110
|
+
event_type VARCHAR NOT NULL,
|
|
111
|
+
data TEXT, -- JSON
|
|
112
|
+
created_at TIMESTAMP
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
CREATE INDEX idx_events_run ON acp_events(run_id);
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Operations
|
|
119
|
+
|
|
120
|
+
### Runs
|
|
121
|
+
|
|
122
|
+
```ruby
|
|
123
|
+
# Save
|
|
124
|
+
storage.save_run(run)
|
|
125
|
+
|
|
126
|
+
# Get
|
|
127
|
+
run = storage.get_run("run-id")
|
|
128
|
+
|
|
129
|
+
# Delete (also deletes events)
|
|
130
|
+
storage.delete_run("run-id")
|
|
131
|
+
|
|
132
|
+
# List with filters
|
|
133
|
+
result = storage.list_runs(
|
|
134
|
+
agent_name: "echo",
|
|
135
|
+
session_id: "session-123",
|
|
136
|
+
limit: 10,
|
|
137
|
+
offset: 0
|
|
138
|
+
)
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Sessions
|
|
142
|
+
|
|
143
|
+
```ruby
|
|
144
|
+
# Save (insert or update)
|
|
145
|
+
storage.save_session(session)
|
|
146
|
+
|
|
147
|
+
# Get
|
|
148
|
+
session = storage.get_session("session-id")
|
|
149
|
+
|
|
150
|
+
# Delete
|
|
151
|
+
storage.delete_session("session-id")
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Events
|
|
155
|
+
|
|
156
|
+
```ruby
|
|
157
|
+
# Add
|
|
158
|
+
storage.add_event("run-id", event)
|
|
159
|
+
|
|
160
|
+
# Get with pagination
|
|
161
|
+
events = storage.get_events("run-id", limit: 100, offset: 0)
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## Connection Management
|
|
165
|
+
|
|
166
|
+
### Connection Pool
|
|
167
|
+
|
|
168
|
+
Sequel automatically manages connection pooling:
|
|
169
|
+
|
|
170
|
+
```ruby
|
|
171
|
+
storage = SimpleAcp::Storage::PostgreSQL.new(
|
|
172
|
+
url: ENV['DATABASE_URL']
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
# Pool is managed automatically
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Close Connection
|
|
179
|
+
|
|
180
|
+
```ruby
|
|
181
|
+
storage.close # Disconnects from database
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Health Check
|
|
185
|
+
|
|
186
|
+
```ruby
|
|
187
|
+
if storage.ping
|
|
188
|
+
puts "PostgreSQL is healthy"
|
|
189
|
+
else
|
|
190
|
+
puts "PostgreSQL connection failed"
|
|
191
|
+
end
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
## Production Configuration
|
|
195
|
+
|
|
196
|
+
### Recommended Setup
|
|
197
|
+
|
|
198
|
+
```ruby
|
|
199
|
+
storage = SimpleAcp::Storage::PostgreSQL.new(
|
|
200
|
+
url: ENV['DATABASE_URL'],
|
|
201
|
+
skip_setup: true # Manage schema via migrations
|
|
202
|
+
)
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### With Connection Options
|
|
206
|
+
|
|
207
|
+
```ruby
|
|
208
|
+
require 'sequel'
|
|
209
|
+
|
|
210
|
+
db = Sequel.connect(
|
|
211
|
+
ENV['DATABASE_URL'],
|
|
212
|
+
max_connections: 10,
|
|
213
|
+
pool_timeout: 10,
|
|
214
|
+
connect_timeout: 5
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
storage = SimpleAcp::Storage::PostgreSQL.new(db: db)
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
## Custom Queries
|
|
221
|
+
|
|
222
|
+
Access the underlying Sequel database:
|
|
223
|
+
|
|
224
|
+
```ruby
|
|
225
|
+
# Get the Sequel database object
|
|
226
|
+
db = storage.instance_variable_get(:@db)
|
|
227
|
+
|
|
228
|
+
# Custom queries
|
|
229
|
+
recent_runs = db[:acp_runs]
|
|
230
|
+
.where(agent_name: "chat")
|
|
231
|
+
.where { created_at > Time.now - 3600 }
|
|
232
|
+
.order(Sequel.desc(:created_at))
|
|
233
|
+
.limit(10)
|
|
234
|
+
.all
|
|
235
|
+
|
|
236
|
+
# Aggregate queries
|
|
237
|
+
stats = db[:acp_runs]
|
|
238
|
+
.group(:agent_name)
|
|
239
|
+
.select { [agent_name, count(*).as(total)] }
|
|
240
|
+
.all
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
## Maintenance
|
|
244
|
+
|
|
245
|
+
### Clear All Data
|
|
246
|
+
|
|
247
|
+
```ruby
|
|
248
|
+
storage.clear! # Truncates all tables
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
### Manual Schema Setup
|
|
252
|
+
|
|
253
|
+
```ruby
|
|
254
|
+
# Skip auto-setup
|
|
255
|
+
storage = SimpleAcp::Storage::PostgreSQL.new(
|
|
256
|
+
url: ENV['DATABASE_URL'],
|
|
257
|
+
skip_setup: true
|
|
258
|
+
)
|
|
259
|
+
|
|
260
|
+
# Run migrations manually in your deployment
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### Vacuum and Analyze
|
|
264
|
+
|
|
265
|
+
```sql
|
|
266
|
+
-- Periodic maintenance
|
|
267
|
+
VACUUM ANALYZE acp_runs;
|
|
268
|
+
VACUUM ANALYZE acp_sessions;
|
|
269
|
+
VACUUM ANALYZE acp_events;
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
### Archive Old Data
|
|
273
|
+
|
|
274
|
+
```sql
|
|
275
|
+
-- Move old runs to archive
|
|
276
|
+
INSERT INTO acp_runs_archive
|
|
277
|
+
SELECT * FROM acp_runs
|
|
278
|
+
WHERE created_at < NOW() - INTERVAL '90 days';
|
|
279
|
+
|
|
280
|
+
DELETE FROM acp_runs
|
|
281
|
+
WHERE created_at < NOW() - INTERVAL '90 days';
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
## Error Handling
|
|
285
|
+
|
|
286
|
+
```ruby
|
|
287
|
+
begin
|
|
288
|
+
run = storage.get_run("run-id")
|
|
289
|
+
rescue Sequel::DatabaseConnectionError
|
|
290
|
+
puts "Database connection failed"
|
|
291
|
+
rescue Sequel::DatabaseError => e
|
|
292
|
+
puts "Database error: #{e.message}"
|
|
293
|
+
end
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
## Performance Tips
|
|
297
|
+
|
|
298
|
+
### Indexes
|
|
299
|
+
|
|
300
|
+
The default schema includes indexes on common query patterns. Add more as needed:
|
|
301
|
+
|
|
302
|
+
```sql
|
|
303
|
+
-- For time-range queries
|
|
304
|
+
CREATE INDEX idx_runs_created ON acp_runs(created_at);
|
|
305
|
+
|
|
306
|
+
-- For status queries
|
|
307
|
+
CREATE INDEX idx_runs_status ON acp_runs(status);
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
### Partitioning
|
|
311
|
+
|
|
312
|
+
For high-volume deployments, consider partitioning:
|
|
313
|
+
|
|
314
|
+
```sql
|
|
315
|
+
-- Partition events by month
|
|
316
|
+
CREATE TABLE acp_events (
|
|
317
|
+
id SERIAL,
|
|
318
|
+
run_id VARCHAR NOT NULL,
|
|
319
|
+
event_type VARCHAR NOT NULL,
|
|
320
|
+
data TEXT,
|
|
321
|
+
created_at TIMESTAMP
|
|
322
|
+
) PARTITION BY RANGE (created_at);
|
|
323
|
+
|
|
324
|
+
CREATE TABLE acp_events_2025_01 PARTITION OF acp_events
|
|
325
|
+
FOR VALUES FROM ('2025-01-01') TO ('2025-02-01');
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
## Best Practices
|
|
329
|
+
|
|
330
|
+
1. **Use connection pooling** - Let Sequel manage connections
|
|
331
|
+
2. **Skip auto-setup in production** - Use migrations instead
|
|
332
|
+
3. **Index appropriately** - Based on your query patterns
|
|
333
|
+
4. **Archive old data** - Keep tables manageable
|
|
334
|
+
5. **Monitor query performance** - Watch for slow queries
|
|
335
|
+
|
|
336
|
+
## Comparison with Other Backends
|
|
337
|
+
|
|
338
|
+
| Feature | PostgreSQL | Redis | Memory |
|
|
339
|
+
|---------|------------|-------|--------|
|
|
340
|
+
| Persistence | Permanent | TTL | None |
|
|
341
|
+
| Multi-process | Yes | Yes | No |
|
|
342
|
+
| Speed | Moderate | Fast | Fastest |
|
|
343
|
+
| Query flexibility | Full SQL | Limited | None |
|
|
344
|
+
| Audit trail | Yes | Limited | No |
|
|
345
|
+
|
|
346
|
+
## Next Steps
|
|
347
|
+
|
|
348
|
+
- Learn about [Redis](redis.md) for caching layer
|
|
349
|
+
- Build a [Custom Backend](custom.md) for special needs
|
|
350
|
+
- Review [Memory](memory.md) for development
|