-
Notifications
You must be signed in to change notification settings - Fork 814
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
optimize WS newhead #1615
optimize WS newhead #1615
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,61 +25,98 @@ | |
subscriptionManager *SubscriptionManager | ||
subscriptonConfig *SubscriptionConfig | ||
|
||
logFetcher *LogFetcher | ||
logFetcher *LogFetcher | ||
newHeadListenersMtx *sync.Mutex | ||
newHeadListeners map[rpc.ID]chan map[string]interface{} | ||
} | ||
|
||
type SubscriptionConfig struct { | ||
subscriptionCapacity int | ||
} | ||
|
||
func NewSubscriptionAPI(tmClient rpcclient.Client, logFetcher *LogFetcher, subscriptionConfig *SubscriptionConfig) *SubscriptionAPI { | ||
logFetcher.filterConfig = &FilterConfig{} | ||
return &SubscriptionAPI{ | ||
func NewSubscriptionAPI(tmClient rpcclient.Client, logFetcher *LogFetcher, subscriptionConfig *SubscriptionConfig, filterConfig *FilterConfig) *SubscriptionAPI { | ||
logFetcher.filterConfig = filterConfig | ||
api := &SubscriptionAPI{ | ||
tmClient: tmClient, | ||
subscriptionManager: NewSubscriptionManager(tmClient), | ||
subscriptonConfig: subscriptionConfig, | ||
logFetcher: logFetcher, | ||
newHeadListenersMtx: &sync.Mutex{}, | ||
newHeadListeners: make(map[rpc.ID]chan map[string]interface{}), | ||
} | ||
id, subCh, err := api.subscriptionManager.Subscribe(context.Background(), NewHeadQueryBuilder(), api.subscriptonConfig.subscriptionCapacity) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. does this need supervision or some mechanism to retry/reconnect (can the subscription die?) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the subscription manager has a retry mechanism (that's what the |
||
if err != nil { | ||
panic(err) | ||
} | ||
go func() { | ||
defer func() { | ||
_ = api.subscriptionManager.Unsubscribe(context.Background(), id) | ||
}() | ||
for { | ||
res := <-subCh | ||
ethHeader, err := encodeTmHeader(res.Data.(tmtypes.EventDataNewBlockHeader)) | ||
if err != nil { | ||
fmt.Printf("error encoding new head event %#v due to %s\n", res.Data, err) | ||
continue | ||
} | ||
api.newHeadListenersMtx.Lock() | ||
for _, c := range api.newHeadListeners { | ||
c := c | ||
go func() { | ||
defer func() { | ||
// if the channel is already closed, sending to it will panic | ||
if err := recover(); err != nil { | ||
return | ||
} | ||
}() | ||
c <- ethHeader | ||
}() | ||
|
||
} | ||
|
||
api.newHeadListenersMtx.Unlock() | ||
} | ||
}() | ||
|
||
return api | ||
} | ||
|
||
func (a *SubscriptionAPI) NewHeads(ctx context.Context) (*rpc.Subscription, error) { | ||
func (a *SubscriptionAPI) NewHeads(ctx context.Context) (s *rpc.Subscription, err error) { | ||
defer recordMetrics("eth_newHeads", time.Now(), err == nil) | ||
Check warning Code scanning / CodeQL Calling the system time Warning
Calling the system time may be a possible source of non-determinism
|
||
notifier, supported := rpc.NotifierFromContext(ctx) | ||
if !supported { | ||
return &rpc.Subscription{}, rpc.ErrNotificationsUnsupported | ||
} | ||
|
||
rpcSub := notifier.CreateSubscription() | ||
subscriberID, subCh, err := a.subscriptionManager.Subscribe(context.Background(), NewHeadQueryBuilder(), a.subscriptonConfig.subscriptionCapacity) | ||
if err != nil { | ||
return nil, err | ||
} | ||
listener := make(chan map[string]interface{}) | ||
|
||
go func() { | ||
defer func() { | ||
_ = a.subscriptionManager.Unsubscribe(context.Background(), subscriberID) | ||
}() | ||
OUTER: | ||
for { | ||
select { | ||
case res := <-subCh: | ||
ethHeader, err := encodeTmHeader(res.Data.(tmtypes.EventDataNewBlockHeader)) | ||
case res := <-listener: | ||
err = notifier.Notify(rpcSub.ID, res) | ||
if err != nil { | ||
return | ||
} | ||
err = notifier.Notify(rpcSub.ID, ethHeader) | ||
if err != nil { | ||
return | ||
break OUTER | ||
} | ||
case <-rpcSub.Err(): | ||
return | ||
break OUTER | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is this the same as There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. no we want to break out of the outer loop (instead of the select clause) |
||
case <-notifier.Closed(): | ||
return | ||
break OUTER | ||
} | ||
} | ||
a.newHeadListenersMtx.Lock() | ||
defer a.newHeadListenersMtx.Unlock() | ||
delete(a.newHeadListeners, rpcSub.ID) | ||
close(listener) | ||
}() | ||
a.newHeadListenersMtx.Lock() | ||
defer a.newHeadListenersMtx.Unlock() | ||
a.newHeadListeners[rpcSub.ID] = listener | ||
|
||
return rpcSub, nil | ||
} | ||
|
||
func (a *SubscriptionAPI) Logs(ctx context.Context, filter *filters.FilterCriteria) (*rpc.Subscription, error) { | ||
func (a *SubscriptionAPI) Logs(ctx context.Context, filter *filters.FilterCriteria) (s *rpc.Subscription, err error) { | ||
defer recordMetrics("eth_logs", time.Now(), err == nil) | ||
Check warning Code scanning / CodeQL Calling the system time Warning
Calling the system time may be a possible source of non-determinism
|
||
notifier, supported := rpc.NotifierFromContext(ctx) | ||
if !supported { | ||
return &rpc.Subscription{}, rpc.ErrNotificationsUnsupported | ||
|
Check warning
Code scanning / CodeQL
Calling the system time Warning