Skip to content

Commit

Permalink
Merge pull request #35 from apechimp/asyncchild-race
Browse files Browse the repository at this point in the history
Asyncchild race
  • Loading branch information
tredman authored Nov 5, 2018
2 parents 7df4c61 + 6d0411c commit 87bb646
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@ language: go
go:
- "1.10"
- "1.9"
script:
- "go test -v ./... -race"
5 changes: 5 additions & 0 deletions trace/trace.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ type Span struct {
isSent bool
isRoot bool
children []*Span
childrenLock sync.Mutex
ev *libhoney.Event
spanID string
parentID string
Expand Down Expand Up @@ -234,6 +235,7 @@ func (s *Span) Send() {
s.AddField(k, v)
}
s.rollupLock.Unlock()
s.childrenLock.Lock()
for _, child := range s.children {
if !child.IsAsync() {
if !child.isSent {
Expand All @@ -242,6 +244,7 @@ func (s *Span) Send() {
}
}
}
s.childrenLock.Unlock()
// now that we're all sent, send the span and all its children.
s.send()
s.isSent = true
Expand Down Expand Up @@ -280,7 +283,9 @@ func (s *Span) CreateChild(ctx context.Context) (context.Context, *Span) {
newSpan.parentID = s.spanID
newSpan.trace = s.trace
newSpan.ev = s.trace.builder.NewEvent()
s.childrenLock.Lock()
s.children = append(s.children, newSpan)
s.childrenLock.Unlock()
ctx = PutSpanInContext(ctx, newSpan)
return ctx, newSpan
}
Expand Down
24 changes: 24 additions & 0 deletions trace/trace_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package trace
import (
"context"
"fmt"
"sync"
"testing"
"time"

Expand Down Expand Up @@ -217,6 +218,24 @@ func TestSpan(t *testing.T) {

}

func TestCreateAsyncSpanDoesNotCauseRaceInSend(t *testing.T) {
setupLibhoney()
ctx, tr := NewTrace(context.Background(), t.Name())
rs := tr.GetRootSpan()

wg := &sync.WaitGroup{}
wg.Add(2)
go func() {
rs.Send()
wg.Done()
}()
go func() {
rs.CreateAsyncChild(ctx)
wg.Done()
}()
wg.Wait()
}

func TestAddFieldDoesNotCauseRaceInSendHooks(t *testing.T) {
samplerHook := func(fields map[string]interface{}) (bool, int) {
for range fields {
Expand All @@ -234,11 +253,14 @@ func TestAddFieldDoesNotCauseRaceInSendHooks(t *testing.T) {

run := make(chan *Span)

wg := &sync.WaitGroup{}
wg.Add(1)
go func() {
for s := range run {
time.Sleep(time.Microsecond)
s.Send()
}
wg.Done()
}()

ctx, tr := NewTrace(context.Background(), "")
Expand All @@ -254,6 +276,8 @@ func TestAddFieldDoesNotCauseRaceInSendHooks(t *testing.T) {
}
}
close(run)
// need to wait here to avoid a race on resetting the SamplerHook
wg.Wait()
}

func setupLibhoney() *libhoney.MockOutput {
Expand Down

0 comments on commit 87bb646

Please sign in to comment.