Skip to content

Commit

Permalink
Merge pull request #93 from anujva/fix_master_defensive_blocking
Browse files Browse the repository at this point in the history
Fix panic on writing to closed channel
  • Loading branch information
tagomoris committed May 3, 2021
2 parents d7b98dd + 869c132 commit a26a84f
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 8 deletions.
27 changes: 19 additions & 8 deletions fluent/fluent.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,12 @@ type msgToSend struct {
type Fluent struct {
Config

dialer dialer
stopRunning chan bool
pending chan *msgToSend
wg sync.WaitGroup
dialer dialer
stopRunning chan bool
pending chan *msgToSend
pendingMutex sync.RWMutex
chanClosed bool
wg sync.WaitGroup

muconn sync.Mutex
conn net.Conn
Expand Down Expand Up @@ -143,10 +145,11 @@ func newWithDialer(config Config, d dialer) (f *Fluent, err error) {

if config.Async {
f = &Fluent{
Config: config,
dialer: d,
pending: make(chan *msgToSend, config.BufferLimit),
stopRunning: make(chan bool, 1),
Config: config,
dialer: d,
pending: make(chan *msgToSend, config.BufferLimit),
pendingMutex: sync.RWMutex{},
stopRunning: make(chan bool, 1),
}
f.wg.Add(1)
go f.run()
Expand Down Expand Up @@ -325,6 +328,9 @@ func (f *Fluent) EncodeData(tag string, tm time.Time, message interface{}) (msg
// Close closes the connection, waiting for pending logs to be sent
func (f *Fluent) Close() (err error) {
if f.Config.Async {
f.pendingMutex.Lock()
f.chanClosed = true
f.pendingMutex.Unlock()
if f.Config.ForceStopAsyncSend {
f.stopRunning <- true
close(f.stopRunning)
Expand All @@ -338,6 +344,11 @@ func (f *Fluent) Close() (err error) {

// appendBuffer appends data to buffer with lock.
func (f *Fluent) appendBuffer(msg *msgToSend) error {
f.pendingMutex.RLock()
defer f.pendingMutex.RUnlock()
if f.chanClosed {
return fmt.Errorf("fluent#appendBuffer: Logger already closed")
}
select {
case f.pending <- msg:
default:
Expand Down
43 changes: 43 additions & 0 deletions fluent/fluent_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"net"
"reflect"
Expand Down Expand Up @@ -572,6 +573,48 @@ func ackRespMsgp(t *testing.T, ack string) string {
return buf.String()
}

func TestNoPanicOnAsyncClose(t *testing.T) {
testcases := []struct {
name string
config Config
shouldError bool
}{
{
name: "Channel closed before write",
config: Config{
Async: true,
},
shouldError: true,
},
{
name: "Channel not closed at all",
config: Config{
Async: true,
},
shouldError: false,
},
}
for _, testcase := range testcases {
t.Run(testcase.name, func(t *testing.T) {
t.Parallel()
d := newTestDialer()
f, err := newWithDialer(testcase.config, d)
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if testcase.shouldError {
f.Close()
}
e := f.EncodeAndPostData("tag_name", time.Unix(1482493046, 0), map[string]string{"foo": "bar"})
if testcase.shouldError {
assert.Equal(t, fmt.Errorf("fluent#appendBuffer: Logger already closed"), e)
} else {
assert.Equal(t, nil, e)
}
})
}
}

func TestCloseOnFailingAsyncReconnect(t *testing.T) {
t.Skip("Broken tests")

Expand Down

0 comments on commit a26a84f

Please sign in to comment.