From 7eba873613586640c757f5e1ab5bf8d2e309bd48 Mon Sep 17 00:00:00 2001 From: Thomas Gummerer Date: Mon, 8 Apr 2024 12:25:30 +0200 Subject: [PATCH] fix a race when StopAtEOF is called Currently when StopAtEOF is called, and we previously encountered an EOF already, we stop reading the file immediately. However when tailing a file, new data might have become available in the meantime, before the StopAtEOF is called. The watcher might however not have notified us about that yet. Instead of exiting immediately if that happens, and leaving the data that's already in the file unread, continue iterating until we get the *next* EOF, as we can be reasonably sure that that's the EOF the user meant to stop at, making sure to read all the data that has been written by the time StopAtEOF is called. --- tail.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tail.go b/tail.go index c962599..0171ebb 100644 --- a/tail.go +++ b/tail.go @@ -293,6 +293,7 @@ func (tail *Tail) tailFileSync() { tail.openReader() + stopOnNextEOF := false // Read line by line. for { // do not seek in named pipes @@ -341,11 +342,24 @@ func (tail *Tail) tailFileSync() { } } + if stopOnNextEOF { + return + } + // When EOF is reached, wait for more data to become // available. Wait strategy is based on the `tail.watcher` // implementation (inotify or polling). err := tail.waitForChanges() if err != nil { + // When StopAtEOF() is called, we + // might have more data to read, that + // the filewatcher might not have + // notified us about. Continue + // reading until we found an EOF + // again, and then exit. + if err == ErrStop && tail.Err() == errStopAtEOF { + stopOnNextEOF = true + } if err != ErrStop { tail.Kill(err) }