Skip to content

Commit 98d7a2d

Browse files
authored
perf(fabricx/finality): batch finality via shared poller (#1849)
Signed-off-by: Evan <evanyan@sign.global>
1 parent 4a3c003 commit 98d7a2d

7 files changed

Lines changed: 796 additions & 89 deletions

File tree

docs/configuration.md

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,12 +74,23 @@ token:
7474
# Only applicable for fabricx networks
7575
# notification: The manager is notified about finality events via a notification service (e.g. for FabricX).
7676
# When a new notification arrives, an event is added to a queue for asynchronous processing.
77-
# When a client subscribes to the manager for a specific transaction, we perform an immediate query to check its status.
77+
# When a client subscribes to the manager for a specific transaction, the transaction joins a pending set
78+
# that the shared poller sweeps with batched status queries (see poller below).
7879
notification:
7980
# workers is the number of goroutines that process events in parallel. Defaults to 10.
8081
workers: 10
8182
# queueSize is the size of the event buffer. Defaults to 1000.
8283
queueSize: 1000
84+
# Only applicable for fabricx networks
85+
# poller: resolves the status of pending transactions with periodic batched committer queries.
86+
poller:
87+
# interval is how often the poller sweeps the pending set. Defaults to 1s.
88+
interval: 1s
89+
# batchSize is the maximum number of txIDs in one committer status query. Defaults to 2000.
90+
batchSize: 2000
91+
# pendingTTL is how long a tx stays pending before its slot is reclaimed.
92+
# It should exceed the longest caller finality timeout. Defaults to 10m.
93+
pendingTTL: 10m
8394

8495
# fabricx configuration for FabricX-specific settings
8596
fabricx:
@@ -426,6 +437,9 @@ Default values:
426437
- delivery.listenerTimeout: 10s
427438
- notification.workers: 10
428439
- notification.queueSize: 1000
440+
- poller.interval: 1s
441+
- poller.batchSize: 2000
442+
- poller.pendingTTL: 10m
429443

430444
---
431445

token/services/network/fabricx/driver.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ func NewDriver(
9999
queryServiceProvider,
100100
finalityProvider,
101101
q,
102+
finality2.NewConfig(configService),
102103
),
103104
llmProvider: lookup2.NewCronNSListenerManagerProvider(
104105
queryServiceProvider,
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/*
2+
Copyright IBM Corp. All Rights Reserved.
3+
4+
SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
package finality
8+
9+
import "time"
10+
11+
const (
12+
// PollInterval is the configuration key for how often the shared poller sweeps the pending set
13+
PollInterval = "token.finality.poller.interval"
14+
// PollBatchSize is the configuration key for how many txIDs go into one committer status query
15+
PollBatchSize = "token.finality.poller.batchSize"
16+
// PendingTTL is the configuration key for how long a tx stays pending before its slot is
17+
// reclaimed; it should exceed the longest caller finality timeout
18+
PendingTTL = "token.finality.poller.pendingTTL"
19+
20+
// DefaultPollInterval is the default sweep interval
21+
DefaultPollInterval = 1 * time.Second
22+
// DefaultPollBatchSize is the default status query batch size
23+
DefaultPollBatchSize = 2000
24+
// DefaultPendingTTL is the default pending slot TTL
25+
DefaultPendingTTL = 10 * time.Minute
26+
)
27+
28+
// ConfigGetter models the configuration getter for the finality poller
29+
type ConfigGetter interface {
30+
// PollInterval returns how often the shared poller sweeps the pending set
31+
PollInterval() time.Duration
32+
// PollBatchSize returns how many txIDs go into one committer status query
33+
PollBatchSize() int
34+
// PendingTTL returns how long a tx stays pending before its slot is reclaimed
35+
PendingTTL() time.Duration
36+
}
37+
38+
// Configuration models the configuration for the finality poller.
39+
//
40+
//go:generate counterfeiter -o mock/configuration.go -fake-name Configuration . Configuration
41+
type Configuration interface {
42+
// GetDuration returns the duration for the given key.
43+
GetDuration(key string) time.Duration
44+
// GetInt returns the int for the given key.
45+
GetInt(key string) int
46+
}
47+
48+
// NewConfig creates a new ConfigGetter that uses the provided Configuration
49+
// interface to retrieve finality poller settings.
50+
func NewConfig(configuration Configuration) *serviceConfig {
51+
return &serviceConfig{configuration: configuration}
52+
}
53+
54+
type serviceConfig struct {
55+
configuration Configuration
56+
}
57+
58+
// PollInterval returns the sweep interval from the configuration.
59+
// If the configured value is not greater than 0, it returns DefaultPollInterval.
60+
func (c *serviceConfig) PollInterval() time.Duration {
61+
if v := c.configuration.GetDuration(PollInterval); v > 0 {
62+
return v
63+
}
64+
65+
return DefaultPollInterval
66+
}
67+
68+
// PollBatchSize returns the status query batch size from the configuration.
69+
// If the configured value is not greater than 0, it returns DefaultPollBatchSize.
70+
func (c *serviceConfig) PollBatchSize() int {
71+
if v := c.configuration.GetInt(PollBatchSize); v > 0 {
72+
return v
73+
}
74+
75+
return DefaultPollBatchSize
76+
}
77+
78+
// PendingTTL returns the pending slot TTL from the configuration.
79+
// If the configured value is not greater than 0, it returns DefaultPendingTTL.
80+
func (c *serviceConfig) PendingTTL() time.Duration {
81+
if v := c.configuration.GetDuration(PendingTTL); v > 0 {
82+
return v
83+
}
84+
85+
return DefaultPendingTTL
86+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
Copyright IBM Corp. All Rights Reserved.
3+
4+
SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
package finality_test
8+
9+
import (
10+
"testing"
11+
"time"
12+
13+
"github.com/LFDT-Panurus/panurus/token/services/network/fabricx/finality"
14+
"github.com/LFDT-Panurus/panurus/token/services/network/fabricx/finality/mock"
15+
"github.com/stretchr/testify/assert"
16+
)
17+
18+
func TestServiceConfig_PollInterval(t *testing.T) {
19+
t.Run("returns value from configuration when > 0", func(t *testing.T) {
20+
m := &mock.Configuration{}
21+
m.GetDurationReturns(2 * time.Second)
22+
cfg := finality.NewConfig(m)
23+
24+
assert.Equal(t, 2*time.Second, cfg.PollInterval())
25+
assert.Equal(t, finality.PollInterval, m.GetDurationArgsForCall(0))
26+
})
27+
28+
t.Run("returns default when not set", func(t *testing.T) {
29+
m := &mock.Configuration{}
30+
cfg := finality.NewConfig(m)
31+
32+
assert.Equal(t, finality.DefaultPollInterval, cfg.PollInterval())
33+
})
34+
}
35+
36+
func TestServiceConfig_PollBatchSize(t *testing.T) {
37+
t.Run("returns value from configuration when > 0", func(t *testing.T) {
38+
m := &mock.Configuration{}
39+
m.GetIntReturns(500)
40+
cfg := finality.NewConfig(m)
41+
42+
assert.Equal(t, 500, cfg.PollBatchSize())
43+
assert.Equal(t, finality.PollBatchSize, m.GetIntArgsForCall(0))
44+
})
45+
46+
t.Run("returns default when not set", func(t *testing.T) {
47+
m := &mock.Configuration{}
48+
cfg := finality.NewConfig(m)
49+
50+
assert.Equal(t, finality.DefaultPollBatchSize, cfg.PollBatchSize())
51+
})
52+
}
53+
54+
func TestServiceConfig_PendingTTL(t *testing.T) {
55+
t.Run("returns value from configuration when > 0", func(t *testing.T) {
56+
m := &mock.Configuration{}
57+
m.GetDurationReturns(time.Hour)
58+
cfg := finality.NewConfig(m)
59+
60+
assert.Equal(t, time.Hour, cfg.PendingTTL())
61+
assert.Equal(t, finality.PendingTTL, m.GetDurationArgsForCall(0))
62+
})
63+
64+
t.Run("returns default when not set", func(t *testing.T) {
65+
m := &mock.Configuration{}
66+
cfg := finality.NewConfig(m)
67+
68+
assert.Equal(t, finality.DefaultPendingTTL, cfg.PendingTTL())
69+
})
70+
}

0 commit comments

Comments
 (0)