kbs 0.0.1 → 0.1.0
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 +4 -4
- data/.github/workflows/deploy-github-pages.yml +52 -0
- data/CHANGELOG.md +68 -2
- data/README.md +235 -334
- data/docs/DOCUMENTATION_STATUS.md +158 -0
- data/docs/advanced/custom-persistence.md +775 -0
- data/docs/advanced/debugging.md +726 -0
- data/docs/advanced/index.md +8 -0
- data/docs/advanced/performance.md +832 -0
- data/docs/advanced/testing.md +691 -0
- data/docs/api/blackboard.md +1157 -0
- data/docs/api/engine.md +978 -0
- data/docs/api/facts.md +1212 -0
- data/docs/api/index.md +12 -0
- data/docs/api/rules.md +1034 -0
- data/docs/architecture/blackboard.md +553 -0
- data/docs/architecture/index.md +277 -0
- data/docs/architecture/network-structure.md +343 -0
- data/docs/architecture/rete-algorithm.md +737 -0
- data/docs/assets/css/custom.css +83 -0
- data/docs/assets/images/blackboard-architecture.svg +136 -0
- data/docs/assets/images/compiled-network.svg +101 -0
- data/docs/assets/images/fact-assertion-flow.svg +117 -0
- data/docs/assets/images/kbs.jpg +0 -0
- data/docs/assets/images/pattern-matching-trace.svg +136 -0
- data/docs/assets/images/rete-network-layers.svg +96 -0
- data/docs/assets/images/system-layers.svg +69 -0
- data/docs/assets/images/trading-signal-network.svg +139 -0
- data/docs/assets/js/mathjax.js +17 -0
- data/docs/examples/expert-systems.md +1031 -0
- data/docs/examples/index.md +9 -0
- data/docs/examples/multi-agent.md +1335 -0
- data/docs/examples/stock-trading.md +488 -0
- data/docs/guides/blackboard-memory.md +558 -0
- data/docs/guides/dsl.md +1321 -0
- data/docs/guides/facts.md +652 -0
- data/docs/guides/getting-started.md +383 -0
- data/docs/guides/index.md +23 -0
- data/docs/guides/negation.md +529 -0
- data/docs/guides/pattern-matching.md +561 -0
- data/docs/guides/persistence.md +451 -0
- data/docs/guides/variable-binding.md +491 -0
- data/docs/guides/writing-rules.md +755 -0
- data/docs/index.md +157 -0
- data/docs/installation.md +156 -0
- data/docs/quick-start.md +228 -0
- data/examples/README.md +2 -2
- data/examples/advanced_example.rb +2 -2
- data/examples/advanced_example_dsl.rb +224 -0
- data/examples/ai_enhanced_kbs.rb +1 -1
- data/examples/ai_enhanced_kbs_dsl.rb +538 -0
- data/examples/blackboard_demo_dsl.rb +50 -0
- data/examples/car_diagnostic.rb +1 -1
- data/examples/car_diagnostic_dsl.rb +54 -0
- data/examples/concurrent_inference_demo.rb +5 -5
- data/examples/concurrent_inference_demo_dsl.rb +363 -0
- data/examples/csv_trading_system.rb +1 -1
- data/examples/csv_trading_system_dsl.rb +525 -0
- data/examples/knowledge_base.db +0 -0
- data/examples/portfolio_rebalancing_system.rb +2 -2
- data/examples/portfolio_rebalancing_system_dsl.rb +613 -0
- data/examples/redis_trading_demo_dsl.rb +177 -0
- data/examples/run_all.rb +50 -0
- data/examples/run_all_dsl.rb +49 -0
- data/examples/stock_trading_advanced.rb +1 -1
- data/examples/stock_trading_advanced_dsl.rb +404 -0
- data/examples/temp.txt +7693 -0
- data/examples/temp_dsl.txt +8447 -0
- data/examples/timestamped_trading.rb +1 -1
- data/examples/timestamped_trading_dsl.rb +258 -0
- data/examples/trading_demo.rb +1 -1
- data/examples/trading_demo_dsl.rb +322 -0
- data/examples/working_demo.rb +1 -1
- data/examples/working_demo_dsl.rb +160 -0
- data/lib/kbs/blackboard/engine.rb +3 -3
- data/lib/kbs/blackboard/fact.rb +1 -1
- data/lib/kbs/condition.rb +1 -1
- data/lib/kbs/dsl/knowledge_base.rb +1 -1
- data/lib/kbs/dsl/variable.rb +1 -1
- data/lib/kbs/{rete_engine.rb → engine.rb} +1 -1
- data/lib/kbs/fact.rb +1 -1
- data/lib/kbs/version.rb +1 -1
- data/lib/kbs.rb +2 -2
- data/mkdocs.yml +181 -0
- metadata +66 -6
- data/examples/stock_trading_system.rb.bak +0 -563
|
@@ -0,0 +1,451 @@
|
|
|
1
|
+
# Persistence Options
|
|
2
|
+
|
|
3
|
+
KBS offers multiple storage backends for persistent facts. This guide helps you choose and configure the right storage for your use case.
|
|
4
|
+
|
|
5
|
+
## Storage Backends
|
|
6
|
+
|
|
7
|
+
### 1. No Persistence (Default)
|
|
8
|
+
|
|
9
|
+
Transient in-memory facts using `KBS::Engine`:
|
|
10
|
+
|
|
11
|
+
```ruby
|
|
12
|
+
engine = KBS::Engine.new
|
|
13
|
+
|
|
14
|
+
# Facts exist only in memory
|
|
15
|
+
engine.add_fact(:sensor, { temp: 28 })
|
|
16
|
+
|
|
17
|
+
# Lost on exit
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
**When to use:**
|
|
21
|
+
- Prototyping
|
|
22
|
+
- Short-lived processes
|
|
23
|
+
- Pure computation (no state retention needed)
|
|
24
|
+
- Testing
|
|
25
|
+
|
|
26
|
+
**Pros:**
|
|
27
|
+
- ✅ Fastest (no I/O)
|
|
28
|
+
- ✅ Zero configuration
|
|
29
|
+
- ✅ Simple
|
|
30
|
+
|
|
31
|
+
**Cons:**
|
|
32
|
+
- ❌ No persistence
|
|
33
|
+
- ❌ Lost on crash
|
|
34
|
+
- ❌ No audit trail
|
|
35
|
+
|
|
36
|
+
### 2. SQLite (Default Persistent)
|
|
37
|
+
|
|
38
|
+
Embedded database using `KBS::Blackboard::Engine`:
|
|
39
|
+
|
|
40
|
+
```ruby
|
|
41
|
+
engine = KBS::Blackboard::Engine.new(db_path: 'kb.db')
|
|
42
|
+
|
|
43
|
+
engine.add_fact(:sensor, { temp: 28 })
|
|
44
|
+
engine.close
|
|
45
|
+
|
|
46
|
+
# Next run
|
|
47
|
+
engine = KBS::Blackboard::Engine.new(db_path: 'kb.db')
|
|
48
|
+
puts engine.facts.size # => 1 (persisted)
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
**When to use:**
|
|
52
|
+
- Single-process applications
|
|
53
|
+
- Moderate fact volumes (< 1M facts)
|
|
54
|
+
- ACID transaction requirements
|
|
55
|
+
- Complete audit trails
|
|
56
|
+
- No external dependencies
|
|
57
|
+
|
|
58
|
+
**Pros:**
|
|
59
|
+
- ✅ Embedded (no server)
|
|
60
|
+
- ✅ ACID guarantees
|
|
61
|
+
- ✅ Durable
|
|
62
|
+
- ✅ Full audit trail
|
|
63
|
+
- ✅ SQL queries available
|
|
64
|
+
|
|
65
|
+
**Cons:**
|
|
66
|
+
- ❌ Slower than Redis
|
|
67
|
+
- ❌ Single writer
|
|
68
|
+
- ❌ Not distributed
|
|
69
|
+
|
|
70
|
+
**Configuration:**
|
|
71
|
+
|
|
72
|
+
```ruby
|
|
73
|
+
engine = KBS::Blackboard::Engine.new(
|
|
74
|
+
db_path: 'kb.db', # Database file path
|
|
75
|
+
journal_mode: 'WAL' # WAL mode for better concurrency
|
|
76
|
+
)
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### 3. Redis (High Performance)
|
|
80
|
+
|
|
81
|
+
In-memory data structure store:
|
|
82
|
+
|
|
83
|
+
```ruby
|
|
84
|
+
require 'kbs/blackboard/persistence/redis_store'
|
|
85
|
+
|
|
86
|
+
store = KBS::Blackboard::Persistence::RedisStore.new(
|
|
87
|
+
url: 'redis://localhost:6379/0'
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
engine = KBS::Blackboard::Engine.new(store: store)
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
**When to use:**
|
|
94
|
+
- High-frequency updates (> 1000 writes/sec)
|
|
95
|
+
- Real-time systems (trading, IoT)
|
|
96
|
+
- Distributed systems (multiple engines)
|
|
97
|
+
- Large fact volumes
|
|
98
|
+
- Speed is critical
|
|
99
|
+
|
|
100
|
+
**Pros:**
|
|
101
|
+
- ✅ 100x faster than SQLite
|
|
102
|
+
- ✅ Distributed (multiple engines share data)
|
|
103
|
+
- ✅ Perfect for real-time
|
|
104
|
+
- ✅ Scalable
|
|
105
|
+
|
|
106
|
+
**Cons:**
|
|
107
|
+
- ❌ Requires Redis server
|
|
108
|
+
- ❌ Volatile by default (enable RDB/AOF for persistence)
|
|
109
|
+
- ❌ No ACID across keys
|
|
110
|
+
- ❌ Less audit trail
|
|
111
|
+
|
|
112
|
+
**Configuration:**
|
|
113
|
+
|
|
114
|
+
```ruby
|
|
115
|
+
store = KBS::Blackboard::Persistence::RedisStore.new(
|
|
116
|
+
url: 'redis://localhost:6379/0',
|
|
117
|
+
namespace: 'kbs', # Key prefix
|
|
118
|
+
ttl: 86400 # Expire facts after 24h (optional)
|
|
119
|
+
)
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
**Redis Persistence Options:**
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
# In redis.conf:
|
|
126
|
+
|
|
127
|
+
# RDB: Point-in-time snapshots
|
|
128
|
+
save 900 1 # Save after 900s if 1 key changed
|
|
129
|
+
save 300 10 # Save after 300s if 10 keys changed
|
|
130
|
+
|
|
131
|
+
# AOF: Append-only file (durability)
|
|
132
|
+
appendonly yes
|
|
133
|
+
appendfsync everysec # Sync to disk every second
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### 4. Hybrid (Best of Both)
|
|
137
|
+
|
|
138
|
+
Combines Redis (speed) with SQLite (durability):
|
|
139
|
+
|
|
140
|
+
```ruby
|
|
141
|
+
require 'kbs/blackboard/persistence/hybrid_store'
|
|
142
|
+
|
|
143
|
+
store = KBS::Blackboard::Persistence::HybridStore.new(
|
|
144
|
+
redis_url: 'redis://localhost:6379/0',
|
|
145
|
+
db_path: 'audit.db'
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
engine = KBS::Blackboard::Engine.new(store: store)
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
**How it works:**
|
|
152
|
+
- **Facts**: Stored in Redis (fast access)
|
|
153
|
+
- **Audit log**: Written to SQLite (durable history)
|
|
154
|
+
- **Messages**: Redis sorted sets (fast priority queue)
|
|
155
|
+
|
|
156
|
+
**When to use:**
|
|
157
|
+
- Production systems requiring both speed and auditing
|
|
158
|
+
- Regulatory compliance (need audit trail)
|
|
159
|
+
- High-frequency updates with history requirements
|
|
160
|
+
- Distributed systems needing accountability
|
|
161
|
+
|
|
162
|
+
**Pros:**
|
|
163
|
+
- ✅ Fast fact access (Redis)
|
|
164
|
+
- ✅ Durable audit trail (SQLite)
|
|
165
|
+
- ✅ Best of both worlds
|
|
166
|
+
- ✅ Can reconstruct from audit log
|
|
167
|
+
|
|
168
|
+
**Cons:**
|
|
169
|
+
- ❌ Requires both Redis and SQLite
|
|
170
|
+
- ❌ More complex setup
|
|
171
|
+
- ❌ Slightly slower writes (dual write)
|
|
172
|
+
|
|
173
|
+
**Configuration:**
|
|
174
|
+
|
|
175
|
+
```ruby
|
|
176
|
+
store = KBS::Blackboard::Persistence::HybridStore.new(
|
|
177
|
+
redis_url: 'redis://localhost:6379/0',
|
|
178
|
+
db_path: 'audit.db',
|
|
179
|
+
audit_facts: true, # Log fact changes to SQLite
|
|
180
|
+
audit_rules: true # Log rule firings to SQLite
|
|
181
|
+
)
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## Choosing a Backend
|
|
185
|
+
|
|
186
|
+
### Decision Tree
|
|
187
|
+
|
|
188
|
+
```
|
|
189
|
+
Need persistence?
|
|
190
|
+
├─ No → KBS::Engine (default)
|
|
191
|
+
└─ Yes
|
|
192
|
+
│
|
|
193
|
+
├─ Need speed > 1000 ops/sec?
|
|
194
|
+
│ ├─ Yes
|
|
195
|
+
│ │ ├─ Need audit trail?
|
|
196
|
+
│ │ │ ├─ Yes → Hybrid Store
|
|
197
|
+
│ │ │ └─ No → Redis Store
|
|
198
|
+
│ │ └─ No → Redis Store
|
|
199
|
+
│ │
|
|
200
|
+
│ └─ No
|
|
201
|
+
│ ├─ Need distributed access?
|
|
202
|
+
│ │ └─ Yes → Redis Store
|
|
203
|
+
│ └─ No → SQLite Store
|
|
204
|
+
│
|
|
205
|
+
└─ Single machine, moderate load?
|
|
206
|
+
└─ SQLite Store
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### By Use Case
|
|
210
|
+
|
|
211
|
+
**IoT / Real-Time Sensors:**
|
|
212
|
+
```ruby
|
|
213
|
+
# High frequency, need speed
|
|
214
|
+
store = KBS::Blackboard::Persistence::RedisStore.new(
|
|
215
|
+
url: 'redis://localhost:6379/0'
|
|
216
|
+
)
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
**Trading Systems:**
|
|
220
|
+
```ruby
|
|
221
|
+
# Speed + audit trail for compliance
|
|
222
|
+
store = KBS::Blackboard::Persistence::HybridStore.new(
|
|
223
|
+
redis_url: 'redis://localhost:6379/0',
|
|
224
|
+
db_path: 'trading_audit.db'
|
|
225
|
+
)
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
**Expert Systems:**
|
|
229
|
+
```ruby
|
|
230
|
+
# Moderate load, need durability
|
|
231
|
+
engine = KBS::Blackboard::Engine.new(db_path: 'expert.db')
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
**Development / Testing:**
|
|
235
|
+
```ruby
|
|
236
|
+
# No persistence needed
|
|
237
|
+
engine = KBS::Engine.new
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
## Migration Between Backends
|
|
241
|
+
|
|
242
|
+
### SQLite → Redis
|
|
243
|
+
|
|
244
|
+
```ruby
|
|
245
|
+
# 1. Load from SQLite
|
|
246
|
+
sqlite_engine = KBS::Blackboard::Engine.new(db_path: 'old.db')
|
|
247
|
+
facts = sqlite_engine.facts
|
|
248
|
+
|
|
249
|
+
# 2. Save to Redis
|
|
250
|
+
redis_store = KBS::Blackboard::Persistence::RedisStore.new(
|
|
251
|
+
url: 'redis://localhost:6379/0'
|
|
252
|
+
)
|
|
253
|
+
redis_engine = KBS::Blackboard::Engine.new(store: redis_store)
|
|
254
|
+
|
|
255
|
+
facts.each do |fact|
|
|
256
|
+
redis_engine.add_fact(fact.type, fact.attributes)
|
|
257
|
+
end
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
### Redis → SQLite
|
|
261
|
+
|
|
262
|
+
```ruby
|
|
263
|
+
# 1. Load from Redis
|
|
264
|
+
redis_store = KBS::Blackboard::Persistence::RedisStore.new(
|
|
265
|
+
url: 'redis://localhost:6379/0'
|
|
266
|
+
)
|
|
267
|
+
redis_engine = KBS::Blackboard::Engine.new(store: redis_store)
|
|
268
|
+
facts = redis_engine.facts
|
|
269
|
+
|
|
270
|
+
# 2. Save to SQLite
|
|
271
|
+
sqlite_engine = KBS::Blackboard::Engine.new(db_path: 'new.db')
|
|
272
|
+
|
|
273
|
+
facts.each do |fact|
|
|
274
|
+
sqlite_engine.add_fact(fact.type, fact.attributes)
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
sqlite_engine.close
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
## Performance Comparison
|
|
281
|
+
|
|
282
|
+
### Write Performance
|
|
283
|
+
|
|
284
|
+
```ruby
|
|
285
|
+
require 'benchmark'
|
|
286
|
+
|
|
287
|
+
# SQLite
|
|
288
|
+
sqlite_engine = KBS::Blackboard::Engine.new(db_path: 'perf.db')
|
|
289
|
+
Benchmark.bm do |x|
|
|
290
|
+
x.report("SQLite writes:") do
|
|
291
|
+
10_000.times { |i| sqlite_engine.add_fact(:test, { value: i }) }
|
|
292
|
+
end
|
|
293
|
+
end
|
|
294
|
+
# ~5,000 ops/sec
|
|
295
|
+
|
|
296
|
+
# Redis
|
|
297
|
+
redis_store = KBS::Blackboard::Persistence::RedisStore.new(
|
|
298
|
+
url: 'redis://localhost:6379/0'
|
|
299
|
+
)
|
|
300
|
+
redis_engine = KBS::Blackboard::Engine.new(store: redis_store)
|
|
301
|
+
Benchmark.bm do |x|
|
|
302
|
+
x.report("Redis writes:") do
|
|
303
|
+
10_000.times { |i| redis_engine.add_fact(:test, { value: i }) }
|
|
304
|
+
end
|
|
305
|
+
end
|
|
306
|
+
# ~50,000 ops/sec (10x faster)
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
### Read Performance
|
|
310
|
+
|
|
311
|
+
```ruby
|
|
312
|
+
# SQLite
|
|
313
|
+
Benchmark.bm do |x|
|
|
314
|
+
x.report("SQLite reads:") do
|
|
315
|
+
10_000.times { sqlite_engine.facts }
|
|
316
|
+
end
|
|
317
|
+
end
|
|
318
|
+
# ~10,000 ops/sec
|
|
319
|
+
|
|
320
|
+
# Redis
|
|
321
|
+
Benchmark.bm do |x|
|
|
322
|
+
x.report("Redis reads:") do
|
|
323
|
+
10_000.times { redis_engine.facts }
|
|
324
|
+
end
|
|
325
|
+
end
|
|
326
|
+
# ~100,000 ops/sec (10x faster)
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
## Custom Persistence
|
|
330
|
+
|
|
331
|
+
Implement your own backend by subclassing `KBS::Blackboard::Persistence::Store`:
|
|
332
|
+
|
|
333
|
+
```ruby
|
|
334
|
+
class PostgresStore < KBS::Blackboard::Persistence::Store
|
|
335
|
+
def save_fact(fact)
|
|
336
|
+
# Insert into PostgreSQL
|
|
337
|
+
end
|
|
338
|
+
|
|
339
|
+
def load_facts(type = nil)
|
|
340
|
+
# Query from PostgreSQL
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
def delete_fact(id)
|
|
344
|
+
# Delete from PostgreSQL
|
|
345
|
+
end
|
|
346
|
+
|
|
347
|
+
def save_message(topic, message, priority)
|
|
348
|
+
# Store message
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
def pop_message(topic)
|
|
352
|
+
# Retrieve highest priority message
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
def log_fact_change(operation, fact)
|
|
356
|
+
# Audit logging
|
|
357
|
+
end
|
|
358
|
+
|
|
359
|
+
def fact_history(fact_id)
|
|
360
|
+
# Get change history
|
|
361
|
+
end
|
|
362
|
+
end
|
|
363
|
+
|
|
364
|
+
# Use custom store
|
|
365
|
+
store = PostgresStore.new(connection_string: "...")
|
|
366
|
+
engine = KBS::Blackboard::Engine.new(store: store)
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
See [Custom Persistence](../advanced/custom-persistence.md) for details.
|
|
370
|
+
|
|
371
|
+
## Configuration Best Practices
|
|
372
|
+
|
|
373
|
+
### SQLite
|
|
374
|
+
|
|
375
|
+
```ruby
|
|
376
|
+
# Enable WAL mode for better concurrency
|
|
377
|
+
engine = KBS::Blackboard::Engine.new(
|
|
378
|
+
db_path: 'kb.db',
|
|
379
|
+
journal_mode: 'WAL',
|
|
380
|
+
synchronous: 'NORMAL', # Trade some durability for speed
|
|
381
|
+
cache_size: -64000 # 64MB cache
|
|
382
|
+
)
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
### Redis
|
|
386
|
+
|
|
387
|
+
```ruby
|
|
388
|
+
# Connection pooling for high concurrency
|
|
389
|
+
store = KBS::Blackboard::Persistence::RedisStore.new(
|
|
390
|
+
url: 'redis://localhost:6379/0',
|
|
391
|
+
pool_size: 10, # Connection pool size
|
|
392
|
+
pool_timeout: 5 # Timeout in seconds
|
|
393
|
+
)
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
### Hybrid
|
|
397
|
+
|
|
398
|
+
```ruby
|
|
399
|
+
# Balance between speed and durability
|
|
400
|
+
store = KBS::Blackboard::Persistence::HybridStore.new(
|
|
401
|
+
redis_url: 'redis://localhost:6379/0',
|
|
402
|
+
db_path: 'audit.db',
|
|
403
|
+
batch_audit_writes: true, # Batch SQLite writes
|
|
404
|
+
audit_batch_size: 100 # Flush every 100 changes
|
|
405
|
+
)
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
## Troubleshooting
|
|
409
|
+
|
|
410
|
+
### SQLite Database Locked
|
|
411
|
+
|
|
412
|
+
```ruby
|
|
413
|
+
# Increase busy timeout
|
|
414
|
+
engine = KBS::Blackboard::Engine.new(
|
|
415
|
+
db_path: 'kb.db',
|
|
416
|
+
busy_timeout: 5000 # Wait up to 5 seconds
|
|
417
|
+
)
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
### Redis Connection Issues
|
|
421
|
+
|
|
422
|
+
```ruby
|
|
423
|
+
# Enable retry logic
|
|
424
|
+
store = KBS::Blackboard::Persistence::RedisStore.new(
|
|
425
|
+
url: 'redis://localhost:6379/0',
|
|
426
|
+
reconnect_attempts: 3,
|
|
427
|
+
reconnect_delay: 1.0
|
|
428
|
+
)
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
### Hybrid Sync Issues
|
|
432
|
+
|
|
433
|
+
```ruby
|
|
434
|
+
# Force synchronous audit writes
|
|
435
|
+
store = KBS::Blackboard::Persistence::HybridStore.new(
|
|
436
|
+
redis_url: 'redis://localhost:6379/0',
|
|
437
|
+
db_path: 'audit.db',
|
|
438
|
+
sync_audit_writes: true # Don't batch, write immediately
|
|
439
|
+
)
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
## Next Steps
|
|
443
|
+
|
|
444
|
+
- **[Blackboard Memory](blackboard-memory.md)** - Using persistent blackboard
|
|
445
|
+
- **[Custom Persistence](../advanced/custom-persistence.md)** - Implementing custom stores
|
|
446
|
+
- **[Performance Guide](../advanced/performance.md)** - Optimizing storage performance
|
|
447
|
+
- **[API Reference](../api/blackboard.md)** - Complete blackboard API
|
|
448
|
+
|
|
449
|
+
---
|
|
450
|
+
|
|
451
|
+
*Choose your backend based on speed, durability, and distribution requirements.*
|