-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add IO::MultiWriter #3404
Add IO::MultiWriter #3404
Conversation
return if @closed | ||
@closed = true | ||
|
||
@writers.each { |writer| writer.close } if sync_close? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can close raise(*)? If so, does that need to be handled?
(*) It is not obvious from reading the code. Flush calls unbuffered write at least in some IO variants that are mixins.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think it needs to be handled. Errors from write calls bubble up to the caller in #write
.
Maybe we should attempt to write to the remaining writers if one call fails? I'm not entirely sure it's beneficial at all, but it should be considered. |
|
||
@writers.each { |writer| writer.write(slice) } | ||
rescue ex | ||
close |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Closing the IO on error seemed a good idea at the time. This comes back to the question on what we should do if one of the IOs raises. Should we attempt to recover or just write off the IO as failed.
Is there realistically any reason why an IO would raise if it wouldn't raise on successive calls? Most IO code is written not to handle exceptions from IO objects, and to simply reconnect if such an event happens.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here's a reason for closing: if one of the write calls fails, then one of the underlying IOs may have written more than the rest. This means that the IOs are no longer consistent, and so we should fail all subsequent calls so that the two IOs don't go out of sync.
Unfortunately this isn't desired behaviour for logging because you don't want stdout to stop when the disk is full, so maybe it should be configurable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For now I'll avoid closing the IO. In other IOs if a write fails the IO doesn't get automatically closed, so I don't think this should be done for this particular IO.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
ce48008
to
8bbb175
Compare
property? sync_close | ||
getter? closed = false | ||
|
||
@writers : Array(IO) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this can be removed as it will be correctly inferred from the constructor below
def write(slice : Slice(UInt8)) | ||
check_open | ||
|
||
@writers.each { |writer| writer.write(slice) } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be @writers.each &.write(slice)
, but you can leave it like this if you prefer it. Same applies to close
8bbb175
to
7260fec
Compare
Updated! |
@RX14 Thank you for this! ❤️ |
Useful for writing log output to multiple locations (stdout + file) or any sort of parallel processing of IO data.