saving in place
This commit is contained in:
@@ -36,14 +36,17 @@ type AdaptiveEndpoint struct {
|
||||
}
|
||||
|
||||
// EndpointMetrics tracks performance metrics for an endpoint
|
||||
// All fields must be 64-bit aligned for atomic access
|
||||
type EndpointMetrics struct {
|
||||
TotalRequests int64
|
||||
SuccessfulRequests int64
|
||||
FailedRequests int64
|
||||
TotalLatency int64 // nanoseconds
|
||||
LastRequestTime int64 // unix timestamp
|
||||
SuccessRate float64
|
||||
AverageLatency float64 // milliseconds
|
||||
// Non-atomic fields - must be protected by mutex when accessed
|
||||
mu sync.RWMutex
|
||||
SuccessRate float64
|
||||
AverageLatency float64 // milliseconds
|
||||
}
|
||||
|
||||
// CircuitBreaker implements circuit breaker pattern for failed endpoints
|
||||
@@ -86,8 +89,13 @@ func NewAdaptiveRateLimiter(cfg *config.ArbitrumConfig, logger *logger.Logger) *
|
||||
// Create adaptive endpoint for primary endpoint
|
||||
arl.addEndpoint(cfg.RPCEndpoint, cfg.RateLimit)
|
||||
|
||||
// Create adaptive endpoints for fallback endpoints
|
||||
for _, endpoint := range cfg.FallbackEndpoints {
|
||||
// Create adaptive endpoints for reading endpoints
|
||||
for _, endpoint := range cfg.ReadingEndpoints {
|
||||
arl.addEndpoint(endpoint.URL, endpoint.RateLimit)
|
||||
}
|
||||
|
||||
// Create adaptive endpoints for execution endpoints
|
||||
for _, endpoint := range cfg.ExecutionEndpoints {
|
||||
arl.addEndpoint(endpoint.URL, endpoint.RateLimit)
|
||||
}
|
||||
|
||||
@@ -231,6 +239,37 @@ func (arl *AdaptiveRateLimiter) getBestEndpoint() string {
|
||||
return bestEndpoint
|
||||
}
|
||||
|
||||
// updateDerivedMetrics safely updates calculated metrics with proper synchronization
|
||||
func (em *EndpointMetrics) updateDerivedMetrics() {
|
||||
totalRequests := atomic.LoadInt64(&em.TotalRequests)
|
||||
successfulRequests := atomic.LoadInt64(&em.SuccessfulRequests)
|
||||
totalLatency := atomic.LoadInt64(&em.TotalLatency)
|
||||
|
||||
em.mu.Lock()
|
||||
defer em.mu.Unlock()
|
||||
|
||||
// Calculate success rate
|
||||
if totalRequests > 0 {
|
||||
em.SuccessRate = float64(successfulRequests) / float64(totalRequests)
|
||||
} else {
|
||||
em.SuccessRate = 0.0
|
||||
}
|
||||
|
||||
// Calculate average latency in milliseconds
|
||||
if totalRequests > 0 {
|
||||
em.AverageLatency = float64(totalLatency) / float64(totalRequests) / 1e6 // ns to ms
|
||||
} else {
|
||||
em.AverageLatency = 0.0
|
||||
}
|
||||
}
|
||||
|
||||
// getCalculatedMetrics safely returns derived metrics
|
||||
func (em *EndpointMetrics) getCalculatedMetrics() (float64, float64) {
|
||||
em.mu.RLock()
|
||||
defer em.mu.RUnlock()
|
||||
return em.SuccessRate, em.AverageLatency
|
||||
}
|
||||
|
||||
// calculateEndpointScore calculates a score for endpoint selection
|
||||
func (arl *AdaptiveRateLimiter) calculateEndpointScore(endpoint *AdaptiveEndpoint) float64 {
|
||||
// Base score on success rate (0-1)
|
||||
@@ -238,13 +277,17 @@ func (arl *AdaptiveRateLimiter) calculateEndpointScore(endpoint *AdaptiveEndpoin
|
||||
latencyWeight := 0.3
|
||||
loadWeight := 0.1
|
||||
|
||||
successScore := endpoint.metrics.SuccessRate
|
||||
// Update derived metrics first
|
||||
endpoint.metrics.updateDerivedMetrics()
|
||||
|
||||
// Get calculated metrics safely
|
||||
successScore, avgLatency := endpoint.metrics.getCalculatedMetrics()
|
||||
|
||||
// Invert latency score (lower latency = higher score)
|
||||
latencyScore := 1.0
|
||||
if endpoint.metrics.AverageLatency > 0 {
|
||||
if avgLatency > 0 {
|
||||
// Normalize latency score (assuming 1000ms is poor, 100ms is good)
|
||||
latencyScore = 1.0 - (endpoint.metrics.AverageLatency / 1000.0)
|
||||
latencyScore = 1.0 - (avgLatency / 1000.0)
|
||||
if latencyScore < 0 {
|
||||
latencyScore = 0
|
||||
}
|
||||
|
||||
@@ -36,8 +36,18 @@ func NewLimiterManager(cfg *config.ArbitrumConfig) *LimiterManager {
|
||||
Config: cfg.RateLimit,
|
||||
}
|
||||
|
||||
// Create limiters for fallback endpoints
|
||||
for _, endpoint := range cfg.FallbackEndpoints {
|
||||
// Create limiters for reading endpoints
|
||||
for _, endpoint := range cfg.ReadingEndpoints {
|
||||
limiter := createLimiter(endpoint.RateLimit)
|
||||
lm.limiters[endpoint.URL] = &EndpointLimiter{
|
||||
URL: endpoint.URL,
|
||||
Limiter: limiter,
|
||||
Config: endpoint.RateLimit,
|
||||
}
|
||||
}
|
||||
|
||||
// Create limiters for execution endpoints
|
||||
for _, endpoint := range cfg.ExecutionEndpoints {
|
||||
limiter := createLimiter(endpoint.RateLimit)
|
||||
lm.limiters[endpoint.URL] = &EndpointLimiter{
|
||||
URL: endpoint.URL,
|
||||
|
||||
Reference in New Issue
Block a user