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 golang-nuts+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to