Skip to content

Commit

Permalink
Deliver async reports from a goroutine pool
Browse files Browse the repository at this point in the history
  • Loading branch information
Angelo Marletta committed May 9, 2024
1 parent 4ae0bc0 commit 2a150d6
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 2 deletions.
10 changes: 10 additions & 0 deletions v2/bugsnag.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"sync"
"time"

"github.com/alitto/pond"
"github.com/bugsnag/bugsnag-go/v2/device"
"github.com/bugsnag/bugsnag-go/v2/errors"
"github.com/bugsnag/bugsnag-go/v2/sessions"
Expand Down Expand Up @@ -39,6 +40,8 @@ var DefaultSessionPublishInterval = 60 * time.Second
var defaultNotifier = Notifier{&Config, nil}
var sessionTracker sessions.SessionTracker

var asyncPool *pond.WorkerPool

// Configure Bugsnag. The only required setting is the APIKey, which can be
// obtained by clicking on "Settings" in your Bugsnag dashboard. This function
// is also responsible for installing the global panic handler, so it should be
Expand All @@ -51,6 +54,7 @@ func Configure(config Configuration) {
// Only do once in case the user overrides the default panichandler, and
// configures multiple times.
panicHandlerOnce.Do(Config.PanicHandler)
setupAsyncPool()
}

// StartSession creates new context from the context.Context instance with
Expand Down Expand Up @@ -253,6 +257,8 @@ func init() {
Logger: log.New(os.Stdout, log.Prefix(), log.Flags()),
PanicHandler: defaultPanicHandler,
Transport: http.DefaultTransport,
NumGoroutines: 10,
MaxPendingReports: 1000,

flushSessionsOnRepanic: true,
})
Expand Down Expand Up @@ -282,3 +288,7 @@ func updateSessionConfig() {
Logger: Config.Logger,
})
}

func setupAsyncPool() {
asyncPool = pond.New(Config.NumGoroutines, Config.MaxPendingReports)
}
23 changes: 23 additions & 0 deletions v2/configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"os"
"path/filepath"
"runtime"
"strconv"
"strings"
)

Expand Down Expand Up @@ -98,9 +99,19 @@ type Configuration struct {
// can be configured if you are in an environment
// that has stringent conditions on making http requests.
Transport http.RoundTripper

// Whether bugsnag should notify synchronously. This defaults to false which
// causes bugsnag-go to spawn a new goroutine for each notification.
Synchronous bool

// Number of goroutines to use for sending notifications in asynchronous
// mode. This defaults to 10.
NumGoroutines int

// The maximum number of reports that can be pending in asynchronous mode.
// This defaults to 1000.
MaxPendingReports int

// Whether the notifier should send all sessions recorded so far to Bugsnag
// when repanicking to ensure that no session information is lost in a
// fatal crash.
Expand Down Expand Up @@ -307,6 +318,18 @@ func (config *Configuration) loadEnv() {
if synchronous := os.Getenv("BUGSNAG_SYNCHRONOUS"); synchronous != "" {
envConfig.Synchronous = synchronous == "1"
}
if numGoroutines := os.Getenv("BUGSNAG_NUM_GOROUTINES"); numGoroutines != "" {
num, err := strconv.Atoi(numGoroutines)
if err != nil {
envConfig.NumGoroutines = num
}
}
if maxPendingReports := os.Getenv("BUGSNAG_MAX_PENDING_REPORTS"); maxPendingReports != "" {
max, err := strconv.Atoi(maxPendingReports)
if err != nil {
envConfig.MaxPendingReports = max
}
}
if disablePanics := os.Getenv("BUGSNAG_DISABLE_PANIC_HANDLER"); disablePanics == "1" {
envConfig.PanicHandler = func() {}
}
Expand Down
1 change: 1 addition & 0 deletions v2/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module github.com/bugsnag/bugsnag-go/v2
go 1.15

require (
github.com/alitto/pond v1.8.3
github.com/bitly/go-simplejson v0.5.1
github.com/bugsnag/panicwrap v1.3.4
github.com/google/uuid v1.6.0
Expand Down
2 changes: 2 additions & 0 deletions v2/go.sum
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
github.com/alitto/pond v1.8.3 h1:ydIqygCLVPqIX/USe5EaV/aSRXTRXDEI9JwuDdu+/xs=
github.com/alitto/pond v1.8.3/go.mod h1:CmvIIGd5jKLasGI3D87qDkQxjzChdKMmnXMg3fG6M6Q=
github.com/bitly/go-simplejson v0.5.1 h1:xgwPbetQScXt1gh9BmoJ6j9JMr3TElvuIyjR8pgdoow=
github.com/bitly/go-simplejson v0.5.1/go.mod h1:YOPVLzCfwK14b4Sff3oP1AmGhI9T9Vsg84etUnlyp+Q=
github.com/bugsnag/panicwrap v1.3.4 h1:A6sXFtDGsgU/4BLf5JT0o5uYg3EeKgGx3Sfs+/uk3pU=
Expand Down
6 changes: 4 additions & 2 deletions v2/report_publisher.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,13 @@ func (*defaultReportPublisher) publishReport(p *payload) error {
return p.deliver()
}

go func(p *payload) {
if !asyncPool.TrySubmit(func() {
if err := p.deliver(); err != nil {
// Ensure that any errors are logged if they occur in a goroutine.
p.logf("bugsnag/defaultReportPublisher.publishReport: %v", err)
}
}(p)
}) {
return fmt.Errorf("failed to submit report to async pool")
}
return nil
}

0 comments on commit 2a150d6

Please sign in to comment.