Skip to content

Commit

Permalink
no race pls
Browse files Browse the repository at this point in the history
  • Loading branch information
technicallyty committed Oct 2, 2024
1 parent f3e990a commit 5cb876d
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 30 deletions.
26 changes: 3 additions & 23 deletions oracle/metrics/dynamic_metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package metrics

import (
"context"
"sync"
"time"

"github.com/skip-mev/connect/v2/oracle/config"
Expand Down Expand Up @@ -38,7 +37,6 @@ type dynamicMetrics struct {
nc NodeClient
impl Metrics
metricsType ImplType
mu sync.RWMutex // Add a mutex for concurrent access
}

func NewDynamicMetrics(ctx context.Context, cfg config.MetricsConfig, nc NodeClient) Metrics {
Expand Down Expand Up @@ -71,14 +69,14 @@ func (d *dynamicMetrics) retrySwitchImpl(ctx context.Context) {
case <-retryDuration.C:
return

Check warning on line 70 in oracle/metrics/dynamic_metrics.go

View check run for this annotation

Codecov / codecov/patch

oracle/metrics/dynamic_metrics.go#L67-L70

Added lines #L67 - L70 were not covered by tests
case <-ticker.C:
// this is technically a race condition, but it doesn't really matter. if something is accessing the
// old impl, its not the end of the world since its a noop impl.
_, err := d.nc.DeriveNodeIdentifier()
if err == nil {
d.mu.Lock()
impl := NewMetricsFromConfig(d.cfg, d.nc)
d.impl = impl
d.metricsType = determineMetricsType(d.impl)
d.metricsType = determineMetricsType(impl)
d.SetConnectBuildInfo()
d.mu.Unlock()
return
}
}
Expand All @@ -87,55 +85,37 @@ func (d *dynamicMetrics) retrySwitchImpl(ctx context.Context) {
}

func (d *dynamicMetrics) AddTick() {
d.mu.RLock()
defer d.mu.RUnlock()
d.impl.AddTick()

Check warning on line 88 in oracle/metrics/dynamic_metrics.go

View check run for this annotation

Codecov / codecov/patch

oracle/metrics/dynamic_metrics.go#L87-L88

Added lines #L87 - L88 were not covered by tests
}

func (d *dynamicMetrics) AddTickerTick(pairID string) {
d.mu.RLock()
defer d.mu.RUnlock()
d.impl.AddTickerTick(pairID)

Check warning on line 92 in oracle/metrics/dynamic_metrics.go

View check run for this annotation

Codecov / codecov/patch

oracle/metrics/dynamic_metrics.go#L91-L92

Added lines #L91 - L92 were not covered by tests
}

func (d *dynamicMetrics) UpdatePrice(name, pairID string, decimals uint64, price float64) {
d.mu.RLock()
defer d.mu.RUnlock()
d.impl.UpdatePrice(name, pairID, decimals, price)

Check warning on line 96 in oracle/metrics/dynamic_metrics.go

View check run for this annotation

Codecov / codecov/patch

oracle/metrics/dynamic_metrics.go#L95-L96

Added lines #L95 - L96 were not covered by tests
}

func (d *dynamicMetrics) UpdateAggregatePrice(pairID string, decimals uint64, price float64) {
d.mu.RLock()
defer d.mu.RUnlock()
d.impl.UpdateAggregatePrice(pairID, decimals, price)

Check warning on line 100 in oracle/metrics/dynamic_metrics.go

View check run for this annotation

Codecov / codecov/patch

oracle/metrics/dynamic_metrics.go#L99-L100

Added lines #L99 - L100 were not covered by tests
}

func (d *dynamicMetrics) AddProviderTick(providerName, pairID string, success bool) {
d.mu.RLock()
defer d.mu.RUnlock()
d.impl.AddProviderTick(providerName, pairID, success)

Check warning on line 104 in oracle/metrics/dynamic_metrics.go

View check run for this annotation

Codecov / codecov/patch

oracle/metrics/dynamic_metrics.go#L103-L104

Added lines #L103 - L104 were not covered by tests
}

func (d *dynamicMetrics) AddProviderCountForMarket(pairID string, count int) {
d.mu.RLock()
defer d.mu.RUnlock()
d.impl.AddProviderCountForMarket(pairID, count)

Check warning on line 108 in oracle/metrics/dynamic_metrics.go

View check run for this annotation

Codecov / codecov/patch

oracle/metrics/dynamic_metrics.go#L107-L108

Added lines #L107 - L108 were not covered by tests
}

func (d *dynamicMetrics) SetConnectBuildInfo() {
d.mu.RLock()
defer d.mu.RUnlock()
d.impl.SetConnectBuildInfo()
}

func (d *dynamicMetrics) MissingPrices(pairIDs []string) {
d.mu.RLock()
defer d.mu.RUnlock()
d.impl.MissingPrices(pairIDs)

Check warning on line 116 in oracle/metrics/dynamic_metrics.go

View check run for this annotation

Codecov / codecov/patch

oracle/metrics/dynamic_metrics.go#L115-L116

Added lines #L115 - L116 were not covered by tests
}

func (d *dynamicMetrics) GetMissingPrices() []string {
d.mu.RLock()
defer d.mu.RUnlock()
return d.impl.GetMissingPrices()

Check warning on line 120 in oracle/metrics/dynamic_metrics.go

View check run for this annotation

Codecov / codecov/patch

oracle/metrics/dynamic_metrics.go#L119-L120

Added lines #L119 - L120 were not covered by tests
}
19 changes: 12 additions & 7 deletions oracle/metrics/dynamic_metrics_test.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
//go:build !race
// +build !race

// we don't need the race detector here because race conditions with the dynamic impl do not matter.
// if a codepath calls `metrics.AddTick()` while the dynamic impl is updating the impl, nothing bad really happens.

package metrics

import (
"context"
"sync"
"testing"
"time"

Expand Down Expand Up @@ -51,15 +56,12 @@ func TestDynamicMetrics_Switches(t *testing.T) {
}
node := mocks.NewNodeClient(t)

// i'm using a mutex to block the DeriveNodeIdentifier call so i can prevent the for/select from looping.
mtx := sync.Mutex{}
mtx.Lock()
blocker := make(chan bool)

// it gets called once in the loop where it checks the node,
// and again in NewMetricsFromConfig.
node.EXPECT().DeriveNodeIdentifier().Run(func() {
mtx.Lock()
mtx.Unlock() //nolint:staticcheck
<-blocker
}).Return("foobar", nil).Twice()

dyn := NewDynamicMetrics(ctx, cfg, node)
Expand All @@ -69,7 +71,10 @@ func TestDynamicMetrics_Switches(t *testing.T) {

dynImpl.cfg.Enabled = true

mtx.Unlock()
// once for the routine that switches it.
blocker <- true
// and again for the new metrics call.
blocker <- true

valid := false
for range 10 {
Expand Down

0 comments on commit 5cb876d

Please sign in to comment.