Skip to content

Commit

Permalink
Merge pull request #430 from SiaFoundation/nate/prevent-panic
Browse files Browse the repository at this point in the history
Prevent price pin failure from crashing node
  • Loading branch information
n8maninger authored Jul 11, 2024
2 parents 29be3ab + ad69b44 commit 2e36a48
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 1 deletion.
2 changes: 1 addition & 1 deletion cmd/hostd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@ func main() {
defer cancel()

if _, err := ex.SiacoinExchangeRate(ctx, "usd"); err != nil {
log.Fatal("failed to get exchange rate", zap.Error(err))
log.Error("failed to get exchange rate. explorer features may not work correctly", zap.Error(err))
}
}

Expand Down
1 change: 1 addition & 0 deletions cmd/hostd/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ func newNode(ctx context.Context, walletKey types.PrivateKey, ex *explorer.Explo
var pm *pin.Manager
if !cfg.Explorer.Disable {
pm, err = pin.NewManager(
pin.WithAlerts(am),
pin.WithStore(db),
pin.WithSettings(sr),
pin.WithExchangeRateRetriever(ex),
Expand Down
7 changes: 7 additions & 0 deletions host/settings/pin/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@ func WithLogger(log *zap.Logger) Option {
}
}

// WithAlerts sets the alerts manager for the pinner to register alerts with.
func WithAlerts(a Alerts) Option {
return func(m *Manager) {
m.alerts = a
}
}

// WithFrequency sets the frequency at which the manager updates the host's
// settings based on the current exchange rate.
func WithFrequency(frequency time.Duration) Option {
Expand Down
35 changes: 35 additions & 0 deletions host/settings/pin/pin.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,14 @@ import (

"github.com/shopspring/decimal"
"go.sia.tech/core/types"
"go.sia.tech/hostd/alerts"
"go.sia.tech/hostd/host/settings"
"go.uber.org/zap"
"lukechampine.com/frand"
)

var pinAlertID = frand.Entropy256()

type (
// A Pin is a pinned price in an external currency.
Pin struct {
Expand Down Expand Up @@ -44,6 +48,12 @@ type (
MaxCollateral Pin `json:"maxCollateral"`
}

// Alerts registers global alerts.
Alerts interface {
Register(alerts.Alert)
Dismiss(...types.Hash256)
}

// A SettingsManager updates and retrieves the host's settings.
SettingsManager interface {
Settings() settings.Settings
Expand All @@ -67,6 +77,7 @@ type (
Manager struct {
log *zap.Logger
store Store
alerts Alerts
explorer ExchangeRateRetriever
sm SettingsManager

Expand Down Expand Up @@ -99,6 +110,26 @@ func averageRate(rates []decimal.Decimal) decimal.Decimal {
return sum.Div(decimal.NewFromInt(int64(len(rates))))
}

func (m *Manager) registerPinFailureAlert(err error) {
if m.alerts != nil && err != nil {
m.alerts.Register(alerts.Alert{
ID: pinAlertID,
Severity: alerts.SeverityError,
Message: "failed to update prices",
Timestamp: time.Now(),
Data: map[string]interface{}{
"error": err.Error(),
},
})
}
}

func (m *Manager) dismissPinFailureAlert() {
if m.alerts != nil {
m.alerts.Dismiss(pinAlertID)
}
}

func (m *Manager) updatePrices(ctx context.Context, force bool) error {
ctx, cancel := context.WithTimeout(ctx, 10*time.Second)
defer cancel()
Expand Down Expand Up @@ -227,6 +258,7 @@ func (m *Manager) Run(ctx context.Context) error {

// update prices immediately
if err := m.updatePrices(ctx, true); err != nil {
m.registerPinFailureAlert(err)
m.log.Error("failed to update prices", zap.Error(err))
}

Expand All @@ -237,6 +269,9 @@ func (m *Manager) Run(ctx context.Context) error {
case <-t.C:
if err := m.updatePrices(ctx, false); err != nil {
m.log.Error("failed to update prices", zap.Error(err))
m.registerPinFailureAlert(err)
} else {
m.dismissPinFailureAlert()
}
}
}
Expand Down

0 comments on commit 2e36a48

Please sign in to comment.