Skip to content

Commit

Permalink
Merge pull request #1380 from lightninglabs/context-guard-go
Browse files Browse the repository at this point in the history
Proof of Concept: Simplifying Concurrency with `ContextGuard.Goroutine`
  • Loading branch information
guggero authored Feb 17, 2025
2 parents 28c4ea8 + eef7461 commit ce1046b
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 21 deletions.
26 changes: 26 additions & 0 deletions fn/context_guard.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,29 @@ func (g *ContextGuard) WithCtxQuitNoTimeout() (context.Context, func()) {

return ctx, cancel
}

// Goroutine runs the given function in a separate goroutine and ensures proper
// error handling. If the object function returns an error, the provided error
// handler is called.
//
// This method also manages the context guard wait group when spawning the
// goroutine.
func (g *ContextGuard) Goroutine(f func() error, errHandler func(error)) {
if f == nil {
panic("no function provided")
}

if errHandler == nil {
panic("no error handler provided")
}

g.Wg.Add(1)
go func() {
defer g.Wg.Done()

err := f()
if err != nil {
errHandler(err)
}
}()
}
38 changes: 17 additions & 21 deletions rfq/negotiator.go
Original file line number Diff line number Diff line change
Expand Up @@ -756,10 +756,7 @@ func (n *Negotiator) HandleIncomingSellAccept(msg rfqmsg.SellAccept,
}

// Query the price oracle asynchronously using a separate goroutine.
n.Wg.Add(1)
go func() {
defer n.Wg.Done()

n.ContextGuard.Goroutine(func() error {
// The sell accept message includes a bid price, which
// represents the amount the peer is willing to pay for the
// asset we are selling.
Expand All @@ -778,14 +775,8 @@ func (n *Negotiator) HandleIncomingSellAccept(msg rfqmsg.SellAccept,
fn.Some(msg.AssetRate),
)
if err != nil {
// The price oracle returned an error. We will return
// without calling the quote accept callback.
err = fmt.Errorf("negotiator failed to query price "+
"oracle when handling incoming sell accept "+
"message: %w", err)
log.Errorf("Error calling price oracle: %v", err)
n.cfg.ErrChan <- err

// The price oracle returned an error.
//
// Construct an invalid quote response event so that we
// can inform the peer that the quote response has not
// validated successfully.
Expand All @@ -798,7 +789,9 @@ func (n *Negotiator) HandleIncomingSellAccept(msg rfqmsg.SellAccept,
),
)

return
return fmt.Errorf("negotiator failed to query price "+
"oracle when handling incoming sell accept "+
"message: %w", err)
}

// The price returned by the oracle may not always align with
Expand All @@ -816,11 +809,8 @@ func (n *Negotiator) HandleIncomingSellAccept(msg rfqmsg.SellAccept,
assetRate.Rate, tolerance,
)
if err != nil {
// The tolerance check failed. We will return without
// calling the quote accept callback.
err = fmt.Errorf("failed to check tolerance: %w", err)
log.Errorf("Error checking tolerance: %v", err)

// The tolerance check failed.
//
// Construct an invalid quote response event so that we
// can inform the peer that the quote response has not
// validated successfully.
Expand All @@ -833,7 +823,7 @@ func (n *Negotiator) HandleIncomingSellAccept(msg rfqmsg.SellAccept,
),
)

return
return fmt.Errorf("failed to check tolerance: %w", err)
}

if !acceptablePrice {
Expand All @@ -857,11 +847,17 @@ func (n *Negotiator) HandleIncomingSellAccept(msg rfqmsg.SellAccept,
),
)

return
return nil
}

finalise(msg, fn.None[InvalidQuoteRespEvent]())
}()
return nil
}, func(err error) {
log.Errorf("Error checking incoming sell accept asset rate: %v",
err)

n.cfg.ErrChan <- err
})
}

// SellOffer is a struct that represents an asset sell offer. This
Expand Down

0 comments on commit ce1046b

Please sign in to comment.