Hi!
I have a simple service that has an API for searching things like log
files. One of the API endpoints returns just the matching documents, while
another will try to return the matching records from those documents.
Because this output could be quite large (and so that results stream) I
pass io.Readers and io.Writers around so that the backend can read from the
input file, filter it as needed, and write it directly to the http response
without having to buffer anything.
A bug was found in that if one of the log files was missing/corrupt the
failure to read it would stop the entire request. To fix this, a 'return
err' in a loop was changed to a log, and I thought all was well. Now, I've
noticed there is a new, subtle problem:
If the write to the http ResponseWriter fails, that error is logged and
skipped as if it was also a transient error.
I've tried to extract the smallest example showing my issue here:
https://play.golang.org/p/i2VVzwAxto8
It uses net/http so you'll have to run it locally.
Essentially, it works like this:
$ curl localhost:8888?q=2
Doc: 1
Doc: 3
Doc: 5
Doc: 7
Doc: 9
For q=2 It will log one error in the middle:
2018/02/06 18:14:59 Error dumping document 6: Unable to read document 6
This is good, since a failure showing document 6 shouldn't prevent 7 and 9
from being output.
The issue is if you hit ?q=3 and control-c curl after a few documents, the
server will continue to try to output documents and log
2018/02/06 18:15:47 Error dumping document 13: write tcp
[::1]:8888->[::1]:52065: write: broken pipe
2018/02/06 18:15:47 Error dumping document 15: write tcp
[::1]:8888->[::1]:52065: write: broken pipe
2018/02/06 18:15:48 Error dumping document 17: write tcp
[::1]:8888->[::1]:52065: write: broken pipe
...
2018/02/06 18:15:48 Error dumping document 27: write tcp
[::1]:8888->[::1]:52065: write: broken pipe
Which is a problem :-)
The actual code in question is
https://github.com/JustinAzoff/flow-indexer/blob/02a1d0f9c7d4107064e925d68cba946ab6c6e359/flowindexer/flowindexer.go#L393
https://github.com/JustinAzoff/flow-indexer/blob/02a1d0f9c7d4107064e925d68cba946ab6c6e359/backend/syslog.go#L61
The problem being that 'Dump' doesn't know the error it got back
from backend.FilterIPs was related to the reading of the log file or the
writing of the data to the response.
What complicates things is some of the backends may potentially use exec,
like this:
https://github.com/JustinAzoff/flow-indexer/blob/02a1d0f9c7d4107064e925d68cba946ab6c6e359/backend/pcap.go#L56
in which case the error comes from cmd.Run.
I think the answer to my problem is somewhere in:
https://dave.cheney.net/2016/04/27/dont-just-check-errors-handle-them-gracefully
but I'm not quite sure the best way to fix this is. Something like
the IsTemporary it describes is along the lines of what I need, if there
was a way to write a isWriteError or isReadError or something.
I was also thinking that an io.Pipe may be one way to solve this, but I'm
not sure if I wouldn't end up back in the same situation with pipes.
--
You received this message because you are subscribed to the Google Groups
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.