Skip to content

Commit b0e00f9

Browse files
committed
improve shutdown handling
1 parent bfeabc7 commit b0e00f9

4 files changed

Lines changed: 56 additions & 6 deletions

File tree

cmd/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ func init() {
132132
rootCmd.Flags().BoolVar(&testMode, "test", false, "Test mode: verify price feed configurations and calculate medians without starting daemon")
133133
rootCmd.Flags().StringVar(&testQueryID, "test-query-id", "", "With --test, only run this custom query id (64-char hex); skips exchange/market tests. Exits non-zero if the query fails.")
134134
// Automatic Unbonding flags
135-
rootCmd.Flags().Uint32("auto-unbonding-frequency", 0, "Enable automatic unbonding every N days (0 = disabled, 1 - 21 days = valid")
135+
rootCmd.Flags().Uint32("auto-unbonding-frequency", 0, "Enable automatic unbonding every N days (0 = disabled, 1 - 21 days = valid)")
136136
rootCmd.Flags().Uint32("auto-unbonding-amount", 0, "Amount of tokens in loya to unbond each unbonding transaction (0 = disabled)")
137137
rootCmd.Flags().String("auto-unbonding-max-stake-percentage", "0.0", "Maximum percentage of stake to unbond each unbonding transaction (0 = disabled, 1.0 = 100%). If unbonding amount exceeds this percentage, we will skip the unbonding transaction until it exceeds this percentage again.")
138138
rootCmd.Flags().Duration("refresh-gas-estimates-interval", 12*time.Hour, "Interval for resetting cached gas estimates and gas-adjustment levels (<=0 disables)")

env.example

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ ETH_RPC_URL_FALLBACK=https://eth-mainnet.g.alchemy.com/v2/YOUR_ALCHEMY_API_KEY
1717
REPORTERS_VALIDATOR_ADDRESS=tellorvaloper1...
1818
WITHDRAW_FREQUENCY=43200
1919

20+
# Auto-balance is configured with CLI flags:
21+
# --auto-balance-to-keep, --auto-balance-execution-time, --auto-balance-bridge-to-eth-addr
22+
2023
# Custom query API keys
2124
# These are used by generated custom_query_config.toml entries that reference ${VAR}.
2225
CMC_PRO_API_KEY=your_coinmarketcap_api_key

reporter/client/reporter_monitors.go

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,7 @@ func (c *Client) MonitorForTippedQueries(ctx context.Context, wg *sync.WaitGroup
229229
}
230230

231231
func (c *Client) WithdrawAndStakeEarnedRewardsPeriodically(ctx context.Context, wg *sync.WaitGroup) {
232+
defer wg.Done()
232233
freqVar := os.Getenv("WITHDRAW_FREQUENCY")
233234
if freqVar == "" {
234235
freqVar = "43200" // default to being 12 hours or 43200 seconds
@@ -240,20 +241,34 @@ func (c *Client) WithdrawAndStakeEarnedRewardsPeriodically(ctx context.Context,
240241
}
241242

242243
for {
244+
select {
245+
case <-ctx.Done():
246+
return
247+
default:
248+
}
249+
243250
valAddr := os.Getenv("REPORTERS_VALIDATOR_ADDRESS")
244251
if valAddr == "" {
245252
fmt.Println("Returning from Withdraw Monitor due to no validator address env variable was found")
246-
time.Sleep(time.Duration(frequency) * time.Second)
253+
select {
254+
case <-ctx.Done():
255+
return
256+
case <-time.After(time.Duration(frequency) * time.Second):
257+
}
247258
continue
248259
}
249260

250261
withdrawMsg := &reportertypes.MsgWithdrawTip{
251262
SelectorAddress: c.accAddr.String(),
252263
ValidatorAddress: valAddr,
253264
}
254-
c.txChan <- TxChannelInfo{Msg: withdrawMsg, isBridge: false, NumRetries: 0, QueryMetaId: 0}
265+
c.trySend(ctx, TxChannelInfo{Msg: withdrawMsg, isBridge: false, NumRetries: 0, QueryMetaId: 0})
255266

256-
time.Sleep(time.Duration(frequency) * time.Second)
267+
select {
268+
case <-ctx.Done():
269+
return
270+
case <-time.After(time.Duration(frequency) * time.Second):
271+
}
257272
}
258273
}
259274

@@ -279,7 +294,7 @@ func (c *Client) AutoUnbondStakePeriodically(ctx context.Context, wg *sync.WaitG
279294
unbondAmount := math.NewInt(int64(amount))
280295
valAddr := os.Getenv("REPORTERS_VALIDATOR_ADDRESS")
281296
if valAddr == "" {
282-
fmt.Println("Returning from Withdraw Monitor due to no validator address env variable was found")
297+
fmt.Println("Returning from Auto Unbond Monitor due to no validator address env variable was found")
283298
return
284299
}
285300
for {
@@ -317,7 +332,7 @@ func (c *Client) AutoUnbondStakePeriodically(ctx context.Context, wg *sync.WaitG
317332
ValidatorAddress: valAddr,
318333
Amount: sdk.NewCoin("loya", unbondAmount),
319334
}
320-
c.txChan <- TxChannelInfo{Msg: unbondMsg, isBridge: false, NumRetries: 0, QueryMetaId: 0}
335+
c.trySend(ctx, TxChannelInfo{Msg: unbondMsg, isBridge: false, NumRetries: 0, QueryMetaId: 0})
321336

322337
}
323338
}

reporter/client/shutdown_test.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,38 @@ func TestStartReporterDaemonTaskLoop_ExitsOnCancelledContext(t *testing.T) {
7878
}
7979
}
8080

81+
func TestWithdrawAndStakeEarnedRewardsPeriodically_ExitsOnCancelledContext(t *testing.T) {
82+
c := NewClient(log.NewNopLogger(), "0.001loya")
83+
ctx, cancel := context.WithCancel(context.Background())
84+
cancel()
85+
86+
var wg sync.WaitGroup
87+
wg.Add(1)
88+
done := make(chan struct{})
89+
go func() {
90+
defer close(done)
91+
c.WithdrawAndStakeEarnedRewardsPeriodically(ctx, &wg)
92+
}()
93+
94+
select {
95+
case <-done:
96+
case <-time.After(2 * time.Second):
97+
t.Fatal("WithdrawAndStakeEarnedRewardsPeriodically did not exit with canceled context")
98+
}
99+
100+
waitDone := make(chan struct{})
101+
go func() {
102+
wg.Wait()
103+
close(waitDone)
104+
}()
105+
106+
select {
107+
case <-waitDone:
108+
case <-time.After(2 * time.Second):
109+
t.Fatal("WithdrawAndStakeEarnedRewardsPeriodically did not call wg.Done")
110+
}
111+
}
112+
81113
// TestConcurrentTrySendDuringShutdown simulates the real shutdown race:
82114
// multiple monitor goroutines try to send to txChan while the context is
83115
// being canceled. None should panic.

0 commit comments

Comments
 (0)