mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-30 23:16:52 +00:00
* [FIX] Enable ws orderbook sync recovery by: - Testing if books have been cleared - Assigning options when loading snapshot * orderbooks: remove setlastupdate method and on select depth method that updates linked list, this reduced lock contention across code base and fixes buffer bug on applying buffered updates * WS - Introduce signaling for the need to fetch the orderbook * Address nits * Update error messages to include exchange name Co-authored-by: shazbert <oharareid.ryan@gmail.com>
This commit is contained in:
@@ -284,9 +284,10 @@ type orderbookManager struct {
|
||||
}
|
||||
|
||||
type update struct {
|
||||
buffer chan *OrderbookUpdateMessage
|
||||
fetchingBook bool
|
||||
initialSync bool
|
||||
buffer chan *OrderbookUpdateMessage
|
||||
fetchingBook bool
|
||||
initialSync bool
|
||||
needsFetchingBook bool
|
||||
}
|
||||
|
||||
// job defines a synchonisation job that tells a go routine to fetch an
|
||||
|
||||
@@ -93,7 +93,7 @@ func (b *Bittrex) UpdateLocalOBBuffer(update *OrderbookUpdateMessage) (bool, err
|
||||
|
||||
err = b.applyBufferUpdate(currencyPair)
|
||||
if err != nil {
|
||||
b.flushAndCleanup(currencyPair)
|
||||
log.Errorf(log.WebsocketMgr, "%s websocket UpdateLocalOBBuffer: Could not apply buffer update\n", b.Name)
|
||||
}
|
||||
|
||||
return false, err
|
||||
@@ -136,23 +136,40 @@ func (b *Bittrex) SeedLocalCacheWithOrderBook(p currency.Pair, sequence int64, o
|
||||
// applyBufferUpdate applies the buffer to the orderbook or initiates a new
|
||||
// orderbook sync by the REST protocol which is off handed to go routine.
|
||||
func (b *Bittrex) applyBufferUpdate(pair currency.Pair) error {
|
||||
fetching, err := b.obm.checkIsFetchingBook(pair)
|
||||
fetching, needsFetching, err := b.obm.handleFetchingBook(pair)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if fetching {
|
||||
return nil
|
||||
}
|
||||
|
||||
recent, err := b.Websocket.Orderbook.GetOrderbook(pair, asset.Spot)
|
||||
if err != nil || (recent.Asks == nil && recent.Bids == nil) {
|
||||
if needsFetching {
|
||||
if b.Verbose {
|
||||
log.Debugf(log.WebsocketMgr, "Orderbook: Fetching via REST\n")
|
||||
log.Debugf(log.WebsocketMgr, "%s Orderbook: Fetching via REST\n", b.Name)
|
||||
}
|
||||
return b.obm.fetchBookViaREST(pair)
|
||||
}
|
||||
recent, err := b.Websocket.Orderbook.GetOrderbook(pair, asset.Spot)
|
||||
if err != nil {
|
||||
log.Errorf(
|
||||
log.WebsocketMgr,
|
||||
"%s error fetching recent orderbook when applying updates: %s\n",
|
||||
b.Name,
|
||||
err)
|
||||
}
|
||||
|
||||
return b.obm.checkAndProcessUpdate(b.ProcessUpdateOB, pair, recent)
|
||||
if recent != nil {
|
||||
err = b.obm.checkAndProcessUpdate(b.ProcessUpdateOB, pair, recent)
|
||||
if err != nil {
|
||||
log.Errorf(
|
||||
log.WebsocketMgr,
|
||||
"%s error processing update - initiating new orderbook sync via REST: %s\n",
|
||||
b.Name,
|
||||
err)
|
||||
b.obm.setNeedsFetchingBook(pair)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SynchroniseWebsocketOrderbook synchronises full orderbook for currency pair
|
||||
@@ -192,12 +209,7 @@ func (b *Bittrex) processJob(p currency.Pair) error {
|
||||
|
||||
// Immediately apply the buffer updates so we don't wait for a
|
||||
// new update to initiate this.
|
||||
err = b.applyBufferUpdate(p)
|
||||
if err != nil {
|
||||
b.flushAndCleanup(p)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
return b.applyBufferUpdate(p)
|
||||
}
|
||||
|
||||
// flushAndCleanup flushes orderbook and clean local cache
|
||||
@@ -239,9 +251,10 @@ func (o *orderbookManager) stageWsUpdate(u *OrderbookUpdateMessage, pair currenc
|
||||
state = &update{
|
||||
// 100ms update assuming we might have up to a 10 second delay.
|
||||
// There could be a potential 100 updates for the currency.
|
||||
buffer: make(chan *OrderbookUpdateMessage, maxWSUpdateBuffer),
|
||||
fetchingBook: false,
|
||||
initialSync: true,
|
||||
buffer: make(chan *OrderbookUpdateMessage, maxWSUpdateBuffer),
|
||||
fetchingBook: false,
|
||||
initialSync: true,
|
||||
needsFetchingBook: true,
|
||||
}
|
||||
m2[a] = state
|
||||
}
|
||||
@@ -258,21 +271,6 @@ func (o *orderbookManager) stageWsUpdate(u *OrderbookUpdateMessage, pair currenc
|
||||
}
|
||||
}
|
||||
|
||||
// checkIsFetchingBook checks status if the book is currently being via the REST
|
||||
// protocol.
|
||||
func (o *orderbookManager) checkIsFetchingBook(pair currency.Pair) (bool, error) {
|
||||
o.Lock()
|
||||
defer o.Unlock()
|
||||
state, ok := o.state[pair.Base][pair.Quote][asset.Spot]
|
||||
if !ok {
|
||||
return false,
|
||||
fmt.Errorf("check is fetching book cannot match currency pair %s asset type %s",
|
||||
pair,
|
||||
asset.Spot)
|
||||
}
|
||||
return state.fetchingBook, nil
|
||||
}
|
||||
|
||||
// stopFetchingBook completes the book fetching.
|
||||
func (o *orderbookManager) stopFetchingBook(pair currency.Pair) error {
|
||||
o.Lock()
|
||||
@@ -292,6 +290,64 @@ func (o *orderbookManager) stopFetchingBook(pair currency.Pair) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// stopNeedsFetchingBook completes the book fetching initiation.
|
||||
func (o *orderbookManager) stopNeedsFetchingBook(pair currency.Pair) error {
|
||||
o.Lock()
|
||||
defer o.Unlock()
|
||||
state, ok := o.state[pair.Base][pair.Quote][asset.Spot]
|
||||
if !ok {
|
||||
return fmt.Errorf("could not match pair %s and asset type %s in hash table",
|
||||
pair,
|
||||
asset.Spot)
|
||||
}
|
||||
if !state.needsFetchingBook {
|
||||
return fmt.Errorf("needs fetching book already set to false for %s %s",
|
||||
pair,
|
||||
asset.Spot)
|
||||
}
|
||||
state.needsFetchingBook = false
|
||||
return nil
|
||||
}
|
||||
|
||||
// setNeedsFetchingBook completes the book fetching initiation.
|
||||
func (o *orderbookManager) setNeedsFetchingBook(pair currency.Pair) error {
|
||||
o.Lock()
|
||||
defer o.Unlock()
|
||||
state, ok := o.state[pair.Base][pair.Quote][asset.Spot]
|
||||
if !ok {
|
||||
return fmt.Errorf("could not match pair %s and asset type %s in hash table",
|
||||
pair,
|
||||
asset.Spot)
|
||||
}
|
||||
state.needsFetchingBook = true
|
||||
return nil
|
||||
}
|
||||
|
||||
// handleFetchingBook checks if a full book is being fetched or needs to be
|
||||
// fetched
|
||||
func (o *orderbookManager) handleFetchingBook(pair currency.Pair) (fetching, needsFetching bool, err error) {
|
||||
o.Lock()
|
||||
defer o.Unlock()
|
||||
state, ok := o.state[pair.Base][pair.Quote][asset.Spot]
|
||||
if !ok {
|
||||
return false, false,
|
||||
fmt.Errorf("check is fetching book cannot match currency pair %s asset type %s",
|
||||
pair,
|
||||
asset.Spot)
|
||||
}
|
||||
|
||||
if state.fetchingBook {
|
||||
return true, false, nil
|
||||
}
|
||||
|
||||
if state.needsFetchingBook {
|
||||
state.needsFetchingBook = false
|
||||
state.fetchingBook = true
|
||||
return false, true, nil
|
||||
}
|
||||
return false, false, nil
|
||||
}
|
||||
|
||||
// completeInitialSync sets if an asset type has completed its initial sync
|
||||
func (o *orderbookManager) completeInitialSync(pair currency.Pair) error {
|
||||
o.Lock()
|
||||
@@ -437,5 +493,6 @@ bufferEmpty:
|
||||
// disable rest orderbook synchronisation
|
||||
_ = o.stopFetchingBook(pair)
|
||||
_ = o.completeInitialSync(pair)
|
||||
_ = o.stopNeedsFetchingBook(pair)
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user