Skip to content

Redis-Synchronized Time for Distributed Circuit Breaker Coordination - #920

Draft
bolshakov wants to merge 7 commits into
feature/use-time-travel-helper-in-testsfrom
feature/use-mocked-redis-time
Draft

Redis-Synchronized Time for Distributed Circuit Breaker Coordination#920
bolshakov wants to merge 7 commits into
feature/use-time-travel-helper-in-testsfrom
feature/use-mocked-redis-time

Conversation

@bolshakov

Copy link
Copy Markdown
Owner

Implement Redis as the authoritative time source for all circuit breaker operations, eliminating time skew issues across multi-instance deployments. This allows Stoplight to reliably coordinate state transitions and metrics aggregation in distributed environments.

Problem

In multi-instance deployments, clock skew between instances can cause:

  • Incorrect state transitions -- out-of-order state changes due to instance clock differences
  • Metrics corruption -- last_error_at / last_success_at timestamps can go backwards
  • Recovery timing issues -- cool-off periods and recovery probes misfire with skewed clocks

The circuit breaker depends on reliable timestamps for its entire state machine and metrics, making time synchronization critical.

Solution

Make Redis the authoritative time source via a now() Lua function that calls redis.call("TIME"):

  • State transitions use now() -- no Ruby timestamps passed to Lua
  • Metrics use now() -- unbounded_metrics and window_metrics synchronized
  • Remove out-of-order protections -- impossible with monotonic Redis time
  • Simplified Lua logic -- cleaner, more maintainable scripts

Architecture

Time flow in distributed deployment:

Instance 1 ──┐
Instance 2 ──┤─→ [Redis Instance] ─→ now() = 1669333004321 (authoritative)
Instance 3 ──┘

All instances call the same now() function, eliminating clock skew.

@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown

Review price tag

🟢 195 effective lines — about 23–59 min (down from 29–72 min) of focused review (based on 200–500 lines/hour). This is within the range where reviewers find the most issues per line, and small changes usually receive feedback the fastest.

Spread across many files. This PR changes 16 files — more than about 9 in 10 PRs touch. Each extra file is another piece of context a reviewer has to load and hold at once.

Why these numbers?

These minutes are what careful defect-finding costs at 200–500 lines/hour — the rate review studies report, not how long a skim takes. "Effective lines" already exclude generated files and lockfiles. Treat the rates and the 200/400 thresholds as guardrails, not laws.

@github-actions github-actions Bot added the proquo: medium ProQuo review price tier: medium label Sep 2, 2026
@bolshakov
bolshakov force-pushed the feature/use-mocked-redis-time branch from 83dad59 to 9ee8232 Compare September 2, 2026 08:50
@github-actions github-actions Bot added proquo: small ProQuo review price tier: small and removed proquo: medium ProQuo review price tier: medium labels Sep 2, 2026
@bolshakov
bolshakov force-pushed the feature/use-mocked-redis-time branch from 9ee8232 to 4b2bb17 Compare September 2, 2026 09:10
@github-actions github-actions Bot added proquo: medium ProQuo review price tier: medium and removed proquo: small ProQuo review price tier: small labels Sep 2, 2026
@bolshakov
bolshakov force-pushed the feature/use-mocked-redis-time branch from 4b2bb17 to 53dd451 Compare September 2, 2026 09:13
@github-actions github-actions Bot added proquo: small ProQuo review price tier: small and removed proquo: medium ProQuo review price tier: medium labels Sep 2, 2026
@bolshakov
bolshakov force-pushed the feature/use-mocked-redis-time branch from 53dd451 to 7846430 Compare September 2, 2026 09:35
@github-actions github-actions Bot added proquo: medium ProQuo review price tier: medium and removed proquo: small ProQuo review price tier: small labels Sep 2, 2026
raise ArgumentError, "Unknown time unit: #{unit}"
end
Timecop.travel(Time.now + seconds)
sleep(seconds)

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no time traveling in feature tests anymore

@bolshakov
bolshakov force-pushed the feature/use-mocked-redis-time branch from 87f78bc to 6a81f63 Compare September 2, 2026 10:10
@github-actions github-actions Bot added proquo: small ProQuo review price tier: small and removed proquo: medium ProQuo review price tier: medium labels Sep 2, 2026
@bolshakov
bolshakov force-pushed the feature/use-mocked-redis-time branch from 6a81f63 to a904df5 Compare September 2, 2026 10:19
Complete implementation of Phase 2a (state transitions) and Phase 2b (metrics)
to use Redis as the authoritative time source across distributed instances.

Changes:
- TimeTravel helper for test time control with Redis stack awareness
- State transition scripts updated to use now()
- Metrics scripts (unbounded/window) updated to use now()
- Float precision preserved in TimeTravel for sub-millisecond accuracy
- All supporting Ruby code updated to match Lua changes

Tests: 832 passing (2 edge cases: rapid-fire updates in same millisecond)
With Redis-synchronized time via now(), out-of-order timestamps are impossible:
- All events on same Redis instance see monotonically increasing time
- Scripts execute serially on Redis
- Time only moves forward

Simplify logic: always update with current timestamp instead of checking
if new timestamp > previous timestamp. This reduces code complexity while
maintaining all functionality.

Tests: All 832 passing
@bolshakov
bolshakov force-pushed the feature/use-mocked-redis-time branch from a904df5 to 5146ac3 Compare September 2, 2026 10:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

proquo: small ProQuo review price tier: small

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant