Skip to content

Architecture Overview

Squirrel Backend is a high-performance FastAPI application designed to manage and monitor EPICS (Experimental Physics and Industrial Control System) process variables (PVs). It handles 40-50K PVs with real-time monitoring, caching, and snapshot capabilities.

The system uses a distributed architecture with separate processes for API serving, PV monitoring, and background task processing, enabling horizontal scaling and fault isolation.

System Architecture

System architecture System architecture

For the full technology stack, see the Home page.

Directory Structure

squirrel-backend/
├── app/                              # Main application package
│   ├── main.py                       # FastAPI entry point (API-only)
│   ├── monitor_main.py               # Standalone PV monitor entry point
│   ├── worker.py                     # Arq worker configuration
│   ├── config.py                     # Pydantic settings management
│   ├── dependencies.py               # FastAPI dependency injection
│   │
│   ├── api/v1/                       # API v1 endpoints
│   │   ├── router.py                 # Main router aggregator
│   │   ├── api_keys.py               # API key management
│   │   ├── pvs.py                    # PV CRUD endpoints
│   │   ├── snapshots.py              # Snapshot operations
│   │   ├── tags.py                   # Tag management
│   │   ├── jobs.py                   # Job status tracking
│   │   ├── health.py                 # Health monitoring
│   │   └── websocket.py              # Real-time PV updates
│   │
│   ├── services/                     # Business logic layer
│   │   ├── api_key_service.py        # API key issuance/validation
│   │   ├── epics_service.py          # EPICS Channel Access (aioca)
│   │   ├── pvaccess_service.py       # EPICS PV Access (p4p)
│   │   ├── pv_protocol.py            # CA/PVA protocol selection
│   │   ├── redis_service.py          # Redis cache management
│   │   ├── pv_monitor.py             # CA monitor (background)
│   │   ├── pvaccess_monitor.py       # PVA monitor (background)
│   │   ├── pv_service.py             # PV business logic
│   │   ├── snapshot_service.py       # Snapshot creation/restore
│   │   ├── tag_service.py            # Tag operations
│   │   ├── job_service.py            # Job tracking
│   │   ├── watchdog.py               # Health monitoring service
│   │   ├── circuit_breaker.py        # EPICS circuit breaker
│   │   ├── subscription_registry.py  # Multi-instance WebSocket support
│   │   ├── bulk_insert_service.py    # PostgreSQL COPY inserts
│   │   ├── background_tasks.py       # Async background jobs
│   │   ├── epics_types.py            # EPICS value type helpers
│   │
│   ├── tasks/                        # Arq task definitions
│   │   └── snapshot_tasks.py         # Snapshot create/restore tasks
│   │
│   ├── repositories/                 # Data access layer
│   │   ├── base.py                   # Base repository class
│   │   ├── api_key_repository.py     # API key storage
│   │   ├── pv_repository.py          # PV database operations
│   │   ├── snapshot_repository.py    # Snapshot storage
│   │   ├── tag_repository.py         # Tag queries
│   │   └── job_repository.py         # Job tracking
│   │
│   ├── models/                       # SQLAlchemy ORM models
│   │   ├── base.py                   # Base model with UUID/timestamps
│   │   ├── api_key.py                # API key model
│   │   ├── pv.py                     # PV model
│   │   ├── snapshot.py               # Snapshot models
│   │   ├── tag.py                    # Tag models
│   │   └── job.py                    # Job model
│   │
│   ├── schemas/                      # Pydantic DTOs
│   │   ├── common.py                 # Shared response shapes
│   │   ├── api_key.py                # API key DTOs
│   │   ├── pv.py                     # PV DTOs
│   │   ├── snapshot.py               # Snapshot DTOs
│   │   ├── tag.py                    # Tag DTOs
│   │   ├── job.py                    # Job DTOs
│   │   └── health.py                 # Health-check DTOs
│   │
│   ├── shared/                       # Cross-process constants
│   │   └── redis_channels.py         # Pub/sub channel names
│   │
│   └── db/                           # Database configuration
│       └── session.py                # Async engine and session factory
├── alembic/                          # Database migrations
├── docker/                           # Docker configuration
├── scripts/                          # Utility scripts
└── tests/                            # Test suite

Design Patterns

Pattern Usage
Repository Abstracts database access in repositories/
Service Layer Business logic separated from API handlers
Dependency Injection FastAPI Depends() for resources
Background Tasks Arq queue for long operations with Job tracking
Singleton Services EPICS, Redis as module-level instances
DTO Pattern Pydantic schemas separate from ORM models
Cache-Aside Redis cache with Watchdog freshness checks
Diff-Based Streaming WebSocket sends only changed PVs
Circuit Breaker Fail-fast on unresponsive IOCs
Leader Election Single PV monitor via Redis lock
Continuation Token Pagination ID-based (not offset) for scalability

Database Models

Data model Data model

Services Layer

Service Responsibility
EPICSService aioca wrapper for caget/caput with circuit breaker
RedisService PV value cache, connection tracking, pub/sub, leader election
PVMonitor Background subscription to all PVs, updates Redis
SnapshotService Create/restore snapshots from cache or EPICS
Watchdog Periodic health checks, reconnection attempts
CircuitBreaker Fail-fast on unresponsive IOCs
SubscriptionRegistry Multi-instance WebSocket subscription tracking
BulkInsertService High-perf PostgreSQL COPY for bulk data

External Services

Service Driver Role
PostgreSQL asyncpg PV metadata, snapshots, tags, jobs
Redis hiredis PV value cache, pub/sub, Arq job queue, monitor leader lock, WebSocket subscription registry
EPICS aioca (CA), p4p (PVA) Read/write/monitor 40K+ process variables