-
Notifications
You must be signed in to change notification settings - Fork 72
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
Ruby: Implement Client#discard! to cleanly dispose of connection post fork #65
Ruby: Implement Client#discard! to cleanly dispose of connection post fork #65
Conversation
…fork If you use `Client#close` on a connection that was inherited from a parent it will close the connection for the parent. Instead we need to use some POSIX magic to close the file descriptor without emitting any close notification, so that the server isn't mislead into closing the connection on its side.
contrib/ruby/ext/trilogy-ruby/cext.c
Outdated
int sock_fd = trilogy_sock_fd(ctx->conn.socket); | ||
if (sock_fd >= 0) { | ||
int null_fd = open("/dev/null", O_RDWR | O_CLOEXEC); | ||
if (null_fd < 0) { | ||
trilogy_syserr_fail_str(errno, rb_str_new_cstr("Failed to open /dev/null")); | ||
return Qfalse; | ||
} | ||
|
||
if (dup2(null_fd, sock_fd) < 0) { | ||
trilogy_syserr_fail_str(errno, rb_str_new_cstr("dup2 failed")); | ||
} | ||
close(null_fd); | ||
} |
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 know if it's better to have all this logic here, or it it would make sense to implement a trilogy_discard
in the C library that could be used by other potential bindings?
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.
IMHO it would make sense to add a method to the C API that handles duping the /dev/null
file descriptor to the socket fd, and returns either TRILOGY_OK
or TRILOGY_SYSERR
, and then the cext could handle raising the ruby error.
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.
Changes make sense to me, although I do feel like we should move the logic to the C API.
contrib/ruby/ext/trilogy-ruby/cext.c
Outdated
int null_fd = open("/dev/null", O_RDWR | O_CLOEXEC); | ||
if (null_fd < 0) { | ||
trilogy_syserr_fail_str(errno, rb_str_new_cstr("Failed to open /dev/null")); | ||
return Qfalse; |
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.
Won't raising in the prior line prevent us from returning false here?
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.
Yeah, it's unreachable, but help making clear we stop here.
contrib/ruby/ext/trilogy-ruby/cext.c
Outdated
int sock_fd = trilogy_sock_fd(ctx->conn.socket); | ||
if (sock_fd >= 0) { | ||
int null_fd = open("/dev/null", O_RDWR | O_CLOEXEC); | ||
if (null_fd < 0) { | ||
trilogy_syserr_fail_str(errno, rb_str_new_cstr("Failed to open /dev/null")); | ||
return Qfalse; | ||
} | ||
|
||
if (dup2(null_fd, sock_fd) < 0) { | ||
trilogy_syserr_fail_str(errno, rb_str_new_cstr("dup2 failed")); | ||
} | ||
close(null_fd); | ||
} |
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.
IMHO it would make sense to add a method to the C API that handles duping the /dev/null
file descriptor to the socket fd, and returns either TRILOGY_OK
or TRILOGY_SYSERR
, and then the cext could handle raising the ruby error.
@adrianna-chang-shopify done. There's now a |
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.
Thanks @casperisfine! Just one question, afterwards I'll merge.
struct trilogy_ctx *ctx = get_ctx(self); | ||
|
||
if (ctx->conn.socket == NULL) { | ||
return Qtrue; |
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.
Curious about returning true here instead of nil -- can you explain your reasoning?
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.
Not a lot of reasoning honestly, I generally return true
on success, but it depends a lot on context. But the return value doesn't matter much here TBH.
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.
But the return value doesn't matter much here TBH.
Yeah that's fair. I'm not sure I'd define calling discard!
on an already-closed connection "successful", but doesn't matter a whole lot as you've said.
If you use
Client#close
on a connection that was inherited from a parent it will close the connection for the parent.Instead we need to use some POSIX magic to close the file descriptor without emitting any close notification, so that the server isn't mislead into closing the connection on its side.
cc @matthewd as we just discussed this.
and cc @adrianna-chang-shopify as the trilogy-adapter will need to be updated to use that new method: https://github.com/github/activerecord-trilogy-adapter/blob/592d98f25ab3e21e0d4f0d9ebc51bb932fd547b3/lib/active_record/connection_adapters/trilogy_adapter.rb#L160