Local (Docker)
The local deployment uses Docker Compose to run Interlock with Redis and Postgres. This is ideal for development, testing, and demo purposes.
Services
The demo/local/docker-compose.yml defines:
| Service | Image | Purpose |
|---|---|---|
redis | redis:7-alpine | Primary state store |
postgres | postgres:16-alpine | Archival storage |
seed | Custom (Go) | Registers pipelines, serves webhook endpoint |
interlock | Custom (Go) | Runs the watcher loop |
Seed Container
The seed container registers pipelines and archetypes at startup, then exposes a webhook server on port 8888 for HTTP triggers to call.
Interlock Container
The interlock container runs the watcher loop. It connects to Redis for state and Postgres for archival. Evaluator scripts are mounted as volumes and run as subprocess evaluators.
Running Locally
cd demo/local
docker compose up -dTo rebuild after code changes:
docker compose up -d --buildEvaluators
The local demo uses shell-script evaluators that read sensor values from Redis:
check-freshness
Reads sensor:freshness from Redis. Returns PASS if the value is below the configured threshold.
#!/bin/bash
VALUE=$(redis-cli -h redis GET sensor:freshness)
if [ "$VALUE" -lt "$THRESHOLD" ]; then
echo '{"status":"PASS","value":{"minutes":'$VALUE'},"reason":"data is fresh"}'
else
echo '{"status":"FAIL","value":{"minutes":'$VALUE'},"reason":"data is stale"}'
ficheck-record-count
Reads sensor:record-count from Redis. Returns PASS if count meets the minimum.
check-upstream
Reads sensor:upstream from Redis. Returns PASS if the upstream pipeline completed.
Setting Sensor Values
Control evaluator outcomes by writing sensor values directly to Redis:
docker compose exec redis redis-cli SET sensor:freshness 15
docker compose exec redis redis-cli SET sensor:record-count 5000
docker compose exec redis redis-cli SET sensor:upstream completedE2E Test Suite
The local E2E tests (demo/local/e2e-test.sh) run 6 scenarios that mirror the AWS E2E suite:
Scenarios
| # | Scenario | Description |
|---|---|---|
| 1 | Progressive readiness | Traits start failing, sensors updated to passing, pipeline triggers |
| 2 | Quality drop re-run | Pipeline completes, quality drops, re-evaluation triggers re-run |
| 3 | Dedup | Same pipeline+date+schedule evaluates only once |
| 4 | Excluded day | Pipeline with exclusion on current day is skipped |
| 5 | Pipeline not found | Non-existent pipeline returns error gracefully |
| 6 | Watcher-driven | Full watcher loop integration (register → evaluate → trigger → complete) |
Running E2E Tests
make local-e2e-testThis runs the full suite and saves results to demo/local/e2e-results/.
Cleanup and Teardown
Between scenarios, run logs are cleaned up to ensure isolation:
docker compose exec redis redis-cli DEL interlock:runlog:my-pipeline:2026-02-23:dailyFull teardown:
make local-e2e-test-teardownThis runs docker compose down -v to remove containers and volumes.
Archival Verification
The E2E suite verifies Postgres archival:
- Archiver interval is set to 30 seconds for testing
- After scenarios complete, wait 35 seconds for archival
- Assert rows exist in
runsandeventsPostgres tables
docker compose exec postgres psql -U interlock -d interlock \
-c "SELECT COUNT(*) FROM runs;"Configuration Files
The local demo mounts configuration from demo/local/:
demo/local/
├── docker-compose.yml
├── interlock.yaml # Watcher configuration
├── pipelines/ # Pipeline YAML definitions
├── archetypes/ # Archetype YAML definitions
├── evaluators/ # Shell script evaluators
├── calendars/ # Calendar YAML files
├── e2e-test.sh # E2E test runner
└── e2e-results/ # Test output (gitignored)