Skip to main content

Storage Architecture

This page provides a comprehensive deep dive into OmniDaemon’s storage architecture, covering what is stored, how it’s stored, and the two production-ready backends: JSON (development) and Redis (production).

What is Stored?

OmniDaemon stores four types of data:

1. Agent Registry

What: Metadata about registered agents Lifetime: Persistent (until explicitly deleted) Purpose: Track which agents are registered, their configuration, and subscription details Data Structure:

2. Task Results

What: Outputs from agent callbacks Lifetime: 24 hours (configurable TTL) Purpose: Store results for retrieval by publishers or other systems Data Structure:
TTL (Time-To-Live):
  • Default: 24 hours (86,400 seconds)
  • Auto-expires (Redis) or manual cleanup (JSON)
  • Balances storage efficiency with result availability

3. Metrics

What: Performance and operational metrics Lifetime: Configurable (default: unlimited, up to 100K entries) Purpose: Track agent performance, debug issues, analyze trends Data Structure:
Event Types:
  • task_received - Agent received task
  • task_processed - Agent completed successfully
  • task_failed - Agent failed to process

4. Configuration

What: System configuration and state Lifetime: Persistent Purpose: Store runtime settings, start time, runner ID, custom settings Data Structure:

Storage Interface (BaseStore)

All storage backends implement the BaseStore abstract class:

Connection Management

Agent Management

Result Management

Metrics Management

Configuration Management

Bulk Operations


JSON Storage (Development)

JSONStore is a file-based storage implementation perfect for local development and testing.

Configuration

Environment Variables:

File Structure

How It Works

In-Memory Cache:
Atomic Writes:
Load on Connect:
Save on Close:

Agent Storage (agents.json)

Structure:
Operations: Add Agent (Upsert):
Get Agent:

Result Storage (results.json)

Structure:
TTL Handling (Manual):

Metrics Storage (metrics.json)

Structure:
Operations:

Configuration Storage (config.json)

Structure:
Operations:

Performance Characteristics

Throughput:
  • Writes: ~1,000 ops/sec (depends on disk speed)
  • Reads: ~10,000 ops/sec (in-memory cache)
Latency:
  • Reads: <1ms (in-memory)
  • Writes: 1-10ms (disk I/O)
Memory Usage:
  • Proportional to data size (all data in memory)
  • ~1KB per agent
  • ~1KB per result
  • ~500 bytes per metric
Storage:
  • Human-readable JSON files
  • Indented for easy inspection
  • ~10-20% overhead vs binary

Pros & Cons

✅ Pros:
  • ✅ No external dependencies (pure Python)
  • ✅ Human-readable (easy to inspect/debug)
  • ✅ Simple setup (just a directory)
  • ✅ Atomic writes (safe file operations)
  • ✅ Fast reads (in-memory cache)
  • ✅ Easy backup (copy directory)
❌ Cons:
  • ❌ Not distributed (single machine only)
  • ❌ No concurrent access from multiple processes
  • ❌ Manual TTL handling (cleanup not automatic)
  • ❌ All data in memory (RAM usage)
  • ❌ Slower writes (disk I/O)
  • ❌ No advanced queries
Use Cases:
  • Local development
  • Testing
  • Single-instance deployments
  • Small-scale production (< 10K agents)

Redis Storage (Production)

RedisStore is a Redis-based storage implementation optimized for production deployments.

Configuration

Environment Variables:

Key Naming Convention

All Redis keys are namespaced with a prefix:
Why Prefix?
  • ✅ Namespace separation (multiple OmniDaemon instances)
  • ✅ Easy cleanup (delete all omni:* keys)
  • ✅ Organized key space
  • ✅ Avoid conflicts with other Redis users

Redis Data Structures Used

1. Hashes - For agents 2. Strings - For results (with TTL) 3. Sets - For topic/agent indexes 4. Sorted Sets - For result index 5. Streams - For metrics

Agent Storage (Redis Hashes)

Keys:
Data Structure:
Output:
Operations: Add Agent (Atomic):
Get Agent:
List Agents for Topic:
Delete Agent (Atomic):

Result Storage (Redis Strings + TTL)

Keys:
Operations: Save Result (with Native TTL):
Get Result (TTL handled by Redis):
List Recent Results:

Metrics Storage (Redis Streams)

Stream:
Why Redis Streams for Metrics?
  • ✅ Time-ordered (perfect for time-series)
  • ✅ Efficient (append-only log)
  • ✅ Durable (persisted)
  • ✅ Queryable (by time range)
  • ✅ Auto-trimming (MAXLEN)
Save Metric:
Get Metrics:

Configuration Storage (Redis Strings)

Keys:
Operations:

Health Check

Performance Characteristics

Throughput:
  • Writes: ~50,000 ops/sec (single instance)
  • Reads: ~100,000 ops/sec (single instance)
  • Cluster: >500,000 ops/sec
Latency:
  • Reads: <1ms
  • Writes: <1ms
  • Network: +1-10ms
Memory Usage:
  • In-memory (RAM)
  • Persistent to disk (optional: AOF, RDB)
  • ~1KB per agent
  • ~1KB per result
  • ~500 bytes per metric
Persistence Options:

Pros & Cons

✅ Pros:
  • ✅ High performance (sub-millisecond)
  • ✅ Distributed access (multiple processes/machines)
  • ✅ Native TTL (automatic expiration)
  • ✅ Atomic operations (thread-safe)
  • ✅ Persistence (AOF/RDB)
  • ✅ Replication & clustering
  • ✅ Efficient data structures
  • ✅ Battle-tested & mature
❌ Cons:
  • ❌ Requires Redis server
  • ❌ RAM usage (all data in memory)
  • ❌ Not human-readable (binary protocol)
  • ❌ Network latency (for remote Redis)
Use Cases:
  • Production deployments
  • Multi-instance setups
  • High throughput requirements
  • Distributed systems
  • Large-scale production (10K+ agents)

Comparison: JSON vs Redis


Data Lifecycle

Agent Persistence

Agents persist until explicitly deleted:
  • Created: sdk.register_agent()
  • Updated: sdk.register_agent() (same name)
  • Deleted: sdk.delete_agent() or sdk.delete_topic()
State Across Restarts:
  • ✅ Agent metadata persisted
  • ✅ Subscription configuration saved
  • ✅ Can restart runner and resume

Result Expiration (24 Hours)

Results auto-expire after 24 hours:
Why 24 Hours?
  • ✅ Balance availability with storage efficiency
  • ✅ Most use cases retrieve results quickly
  • ✅ Prevents unbounded storage growth
  • ✅ Encourages proper result handling
Customizable:

Metric Retention

Metrics kept up to limit:
  • JSON: Last 10,000 metrics
  • Redis: Last 100,000 metrics
Oldest metrics trimmed:

Monitoring Storage

Via CLI

Via SDK

Via Redis CLI (Redis backend only)


Best Practices

1. Choose Right Backend

2. Monitor Storage Health

3. Handle Result Expiration

4. Configure Appropriate TTL

5. Clean Up Old Data

6. Backup Regularly

JSON:
Redis:

Future Backends

PostgreSQL 🚧

Configuration:
Benefits:
  • ACID transactions
  • Complex queries
  • Full-text search
  • Mature ecosystem

MongoDB 🚧

Configuration:
Benefits:
  • Schema flexibility
  • Document storage
  • Horizontal scaling
  • Aggregation pipelines

Amazon S3 🚧

Configuration:
Benefits:
  • Unlimited storage
  • Very cost-effective
  • High durability
  • Lifecycle policies

Further Reading


Summary

What’s Stored:
  1. Agent Registry - Metadata about registered agents (persistent)
  2. Task Results - Agent outputs (24-hour TTL)
  3. Metrics - Performance data (last 10K-100K entries)
  4. Configuration - System settings (persistent)
Backends:
  • JSON - File-based, development, single-instance
  • Redis - In-memory, production, distributed
Key Differences: Storage Size Estimates:
  • 1 agent = ~1KB
  • 1 result = ~1KB
  • 1 metric = ~500 bytes
Best Practices:
  • Use JSON for development
  • Use Redis for production
  • Monitor health regularly
  • Handle result expiration
  • Backup regularly
Storage is the foundation of OmniDaemon’s persistence layer! 💾✨