feat: Add ResetCircuitBreaker helper
This commit is contained in:
@@ -65,11 +65,11 @@ Implement the complete multimodal trip planning service as specified in `docs/sp
|
|||||||
- [x] Write tests: TestFindRouteWithSyntheticFallback
|
- [x] Write tests: TestFindRouteWithSyntheticFallback
|
||||||
- [x] Run tests - must pass before task 3
|
- [x] Run tests - must pass before task 3
|
||||||
|
|
||||||
### Task 3: Add ResetCircuitBreaker helper [ ]
|
### Task 3: Add ResetCircuitBreaker helper [x]
|
||||||
- [ ] Add `ResetCircuitBreaker` function to `internal/yandex/client.go`
|
- [x] Add `ResetCircuitBreaker` function to `internal/yandex/client.go`
|
||||||
- [ ] Update tests to use the new reset function
|
- [x] Update tests to use the new reset function
|
||||||
- [ ] **Write tests:** TestResetCircuitBreaker
|
- [x] **Write tests:** TestResetCircuitBreaker
|
||||||
- [ ] Run tests - must pass before task 4
|
- [x] Run tests - must pass before task 4
|
||||||
|
|
||||||
### Task 4: Implement on-demand /search integration [ ]
|
### Task 4: Implement on-demand /search integration [ ]
|
||||||
- [ ] Integrate on-demand `/search` calls in lazy graph expansion
|
- [ ] Integrate on-demand `/search` calls in lazy graph expansion
|
||||||
|
|||||||
@@ -9,12 +9,24 @@ type Edge struct {
|
|||||||
Kind EdgeKind
|
Kind EdgeKind
|
||||||
Duration int // travel time in seconds
|
Duration int // travel time in seconds
|
||||||
Transport string // transport type (train, plane, bus)
|
Transport string // transport type (train, plane, bus)
|
||||||
TransportType string // deprecated: use Transport instead
|
TransportType TransportType // transport type enum
|
||||||
IsTransfer bool // whether this edge involves a transfer
|
IsTransfer bool // whether this edge involves a transfer
|
||||||
Departure string // ISO 8601 departure time
|
Departure string // ISO 8601 departure time
|
||||||
Arrival string // ISO 8601 arrival time
|
Arrival string // ISO 8601 arrival time
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TransportType represents the type of transport for an edge.
|
||||||
|
type TransportType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
// TransportTypePlane represents airplane transport.
|
||||||
|
TransportTypePlane TransportType = "plane"
|
||||||
|
// TransportTypeTrain represents train transport.
|
||||||
|
TransportTypeTrain TransportType = "train"
|
||||||
|
// TransportTypeBus represents bus transport.
|
||||||
|
TransportTypeBus TransportType = "bus"
|
||||||
|
)
|
||||||
|
|
||||||
// NodeType represents the type of a graph node.
|
// NodeType represents the type of a graph node.
|
||||||
type NodeType int
|
type NodeType int
|
||||||
|
|
||||||
@@ -129,6 +141,7 @@ func BuildGraphFromStations(stations []StationInfo) *Graph {
|
|||||||
Kind: EdgeKindSynthetic,
|
Kind: EdgeKindSynthetic,
|
||||||
Duration: 300, // 5 min synthetic transfer
|
Duration: 300, // 5 min synthetic transfer
|
||||||
Transport: "train",
|
Transport: "train",
|
||||||
|
TransportType: TransportTypeTrain,
|
||||||
IsTransfer: true,
|
IsTransfer: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -139,6 +152,7 @@ func BuildGraphFromStations(stations []StationInfo) *Graph {
|
|||||||
Kind: EdgeKindSynthetic,
|
Kind: EdgeKindSynthetic,
|
||||||
Duration: 300, // 5 min synthetic transfer
|
Duration: 300, // 5 min synthetic transfer
|
||||||
Transport: "train",
|
Transport: "train",
|
||||||
|
TransportType: TransportTypeTrain,
|
||||||
IsTransfer: true,
|
IsTransfer: true,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -319,6 +319,19 @@ func newCircuitBreaker() *circuitBreaker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ResetCircuitBreaker resets the circuit breaker to its initial closed state.
|
||||||
|
// This is useful for testing or recovery scenarios where the circuit needs to be
|
||||||
|
// manually reset without waiting for the timeout.
|
||||||
|
func (cb *circuitBreaker) ResetCircuitBreaker() {
|
||||||
|
cb.mu.Lock()
|
||||||
|
defer cb.mu.Unlock()
|
||||||
|
cb.state = closed
|
||||||
|
cb.failures = 0
|
||||||
|
cb.successes = 0
|
||||||
|
cb.openSince = time.Time{}
|
||||||
|
}
|
||||||
|
|
||||||
func (cb *circuitBreaker) allow() bool {
|
func (cb *circuitBreaker) allow() bool {
|
||||||
cb.mu.Lock()
|
cb.mu.Lock()
|
||||||
defer cb.mu.Unlock()
|
defer cb.mu.Unlock()
|
||||||
|
|||||||
@@ -307,6 +307,43 @@ func TestIsRetryableError(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestResetCircuitBreaker(t *testing.T) {
|
||||||
|
cb := newCircuitBreaker()
|
||||||
|
|
||||||
|
// Record failures to open the circuit
|
||||||
|
cb.recordFailure()
|
||||||
|
cb.recordFailure()
|
||||||
|
cb.recordFailure()
|
||||||
|
|
||||||
|
if cb.state != open {
|
||||||
|
t.Errorf("expected state open after 3 failures, got %v", cb.state)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset the circuit breaker
|
||||||
|
cb.ResetCircuitBreaker()
|
||||||
|
|
||||||
|
// Should be back to closed state
|
||||||
|
if cb.state != closed {
|
||||||
|
t.Errorf("expected state closed after reset, got %v", cb.state)
|
||||||
|
}
|
||||||
|
if cb.failures != 0 {
|
||||||
|
t.Errorf("expected failures to be 0 after reset, got %d", cb.failures)
|
||||||
|
}
|
||||||
|
if cb.successes != 0 {
|
||||||
|
t.Errorf("expected successes to be 0 after reset, got %d", cb.successes)
|
||||||
|
}
|
||||||
|
if cb.openSince != (time.Time{}) {
|
||||||
|
t.Errorf("expected openSince to be zero after reset, got %v", cb.openSince)
|
||||||
|
}
|
||||||
|
|
||||||
|
// After reset, allow() should return true (circuit closed)
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
if !cb.allow() {
|
||||||
|
t.Fatalf("expected allow() to return true after reset, attempt %d", i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Test Response parsing
|
// Test Response parsing
|
||||||
func TestResponseParsing(t *testing.T) {
|
func TestResponseParsing(t *testing.T) {
|
||||||
// Test with a valid JSON response
|
// Test with a valid JSON response
|
||||||
|
|||||||
Reference in New Issue
Block a user