-
Notifications
You must be signed in to change notification settings - Fork 69
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
Refactor error classes #15
Refactor error classes #15
Conversation
@jhawthorn @composerinteralia @matthewd we're looking to get the ball rolling on this work again. Do y'all have any feedback in the meantime? Thanks ❤️ cc @paarthmadan |
I can take a look early next week if nobody beats me to it. I vaguely remember liking this change, if that helps at all 😄. |
This looks promising to me so far. My only concern is compatibility with https://github.com/github/activerecord-trilogy-adapter/blob/000ed42f5023e447b2c28e970fcd1fbac325232c/lib/trilogy_adapter/lost_connection_exception_translator.rb, and one custom bit of translation we've got at GitHub for retrying timeouts on connect, roughly: def connect
Trilogy.new(config)
rescue Errno::ETIMEDOUT, Errno::ECONNREFUSED, Errno::ECONNRESET => error
raise ActiveRecord::ConnectionNotEstablished.new(error.message) I think this change will ultimately simplify all that, but I'd just want to be careful to not accidentally lose any of our reconnection handling along the way.
I know we've got adapter code that rescues and translates EPIPE, ETIMEDOUT, ECONNREFUSED, and ECONNRESET, so having Trilogy-specific for those in particular seems helpful.
Here's an example: In theory we could raise different errors for different error_codes, but I'm not sure how practical that is since there are lots of them. |
Hey @composerinteralia , thank you for the feedback! 🙇♀️
Given @byroot 's approach using modules, I think backwards compatibility should be retained, since all of the error classes will still inherit from the original error classes. In moving towards just
I'm curious why this translation bit wasn't upstreamed into the AR adapter for Trilogy. I thought it was odd that underlying errors like
@byroot do you remember -- was the issue here that we're calling
Would it make sense to do something more similar to what mysql2 does and map explicit error codes to |
It's been a while. But the issue with careful auditing might reduce this to a handful, but it's a lot of work and error prone. |
So maybe in our first pass at this, we leave |
👍🏻 I'm probably unnecessarily worried.
Good question. I think we were in a rush to fix a bug and then never revisited it. From my commit message for that change:
Yeah, I think that'd be OK, especially if we have a well-known list we can draw from. |
7ed2578
to
b81d3ed
Compare
Okay, so following the feedback from our last conversation, we've:
This is ready for another round of feedback. I'll work on changes to the adapter afterwards, but it would be good to have a conversation about how much leeway we have to make breaking changes to translating errors in the adapter / what that process should look like. |
contrib/ruby/lib/trilogy.rb
Outdated
class ProtocolError < BaseError | ||
ERROR_CODES = { | ||
1205 => TimeoutError, # ER_LOCK_WAIT_TIMEOUT | ||
1044 => ConnectionError, # ER_DBACCESS_DENIED_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.
I just realized. We can't raise ConnectionError
as it's a module. We'll need to create another error that include that module.
We should also probably try to cover that path.
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.
Ah good catch 👍 On it
3e7897b
to
3d1b403
Compare
3d1b403
to
5c4efc2
Compare
I think it's fine to make breaking changes—there's probably not too much use of this library outside GitHub yet. It'd be helpful to get a corresponding activerecord-trilogy-adapter branch that passes with these changes so we can run it all against our CI before merging. |
I can absolutely do that! |
665af34
to
f2ad5bd
Compare
@haldun is running these changes against GitHub CI. We'll let you know if anything comes up. |
GitHub CI passing after renaming a couple things 👍🏻 |
rows.count | ||
end | ||
class Result | ||
attr_reader :fields, :rows, :query_time |
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.
Just noticed these warnings in the activerecord-trilogy-adapter tests:
warning: method redefined; discarding old fields
warning: method redefined; discarding old rows
warning: method redefined; discarding old query_time
Defining these in Ruby seems good to me, but then I assume we'll need to remove the rb_define_attr
s in cext.c.
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!
d71d463
to
468e457
Compare
Fix: trilogy-libraries#11 The goals are: - Not raise any error that isn't a descendant of `Trilogy::Error`. - Have a clear distinction between transient network errors that may be retried, and invalid queries that shouldn't. Unsolved issues (yet) - Trilogy calls `rb_syserr_fail_str` in a few places. Meaning it can still raise any of the `Errno::*` errors. - `handle_trilogy_error` raise all `TRILOGY_ERR` as `ProtocolError` which is a `ConnectionError`, but I'm not certain none of the possible errors could be considered client errors.
Instead of raising all ProtocolErrors as connection errors, we use the SQL error code to determine the type of error to raise when handling the Trilogy error in the Ruby bindings. The mapping of error codes to error classes was taken from the mysql2 implementation: https://github.com/brianmario/mysql2/blob/master/lib/mysql2/error.rb#L13-L27 Note that we don't need to care about the 2xxx errors because those are raised by the libmysql client, which Trilogy doesn't deal with. Co-authored-by: Jean Boussier <jean.boussier@shopify.com>
468e457
to
c56494e
Compare
CI keeps getting cancelled (timing out?) for some reason. Retrying again. Once it's green I'll merge. Update: I don't think rerunning is going to help, at least at the moment. I'm seeing some weirdness on another branch as well (it's suddenly taking a really long time to install packages), although most of those test did pass eventually: https://github.com/github/trilogy/compare/trigger-ci?expand=1. I'll see if I can run these locally. |
I've got a patch that I think should get things passing, but realized I can't push to your branch. Could you apply this and I'll kick off the CI builds again? Patch
|
Thanks. Applied in 1a9ab90 |
Looks like I'm going to merge and look into that separately (it does not reproduce consistently with the same seed, unfortunately). If the flakiness is disruptive in the meantime we may need to remove that test. |
Oh interesting that it fails on main 🤔 I thought maybe we needed to add a case to the switch statement in Anyways, thanks for getting this shipped -- I'm going to start working on the next iteration of this. I think we'll need to look at:
|
(Hi - I'm Lorin Thwaits, the guy adding AR 6.1 and 7.0 compatibility to Trilogy. Long time litener / first time caller!) The Python folks had this same PROTOCOL_VIOLATION error unexpectedly surface starting with the release of MySQL 8.0.24 -- a MySQL bug had been fixed at that point and the change notes for that release indicate: |
👋 Hi @lorint , thanks for supplying some extra context! Do you know if the Python folks were experiencing flakiness as well, or was the I suspect this might be something different though, I don't believe Trilogy supports prepared statements yet 🤔 |
I think it was a consistent failure they were seeing. With this new patch in place then running our suite on 8.0 I get a perfectly consistent failure. Somewhat fast and multithreaded machine -- Macbook M1. |
Do you have an example of a test that's failing consistently from your suite? I can't get |
@adrianna-chang-shopify - Now that I went back to check this out I see that I have mis-spoken! The failure I had seen was after I had merged in your ARTA PR "Translate new error classes" along with my compatibility PR, on this line: But now it's been fixed and merged upstream here in this PR on the Trilogy gem. Have just done the same thing again and everything works :) |
There is a new generic Trilogy::ClientError class established with this PR which is useful to provide full AR 7.0 support: trilogy-libraries/trilogy#15
#15 changed the error class for TRILOGY_ERR from `DatabaseError` to `ProtocolError`. This commit reintroduces `DatabaseError` as an ancestor of `ProtocolError` for compatibility reasons, so that rescuing `DatabaseError` still works as before. Note that even with this change there are a number of error codes (see ProtocolError::ERROR_CODES) that are no longer `DatabaseError`s, since we have explicitly recategorized them as `BaseConnectionError`, `TimeoutError`, or `QueryError`.
This commit makes a few changes to our trilogy error translation: * trilogy-libraries/trilogy#118 introduced `Trilogy::EOFError` which we can use instead of matching on `TRILOGY_CLOSED_CONNECTION`. * trilogy-libraries/trilogy#15 introduced `Trilogy::ConnectionClosed`, which inherits from `IOError` for backwards compatibility. As far as I can tell that's the only `IOError` trilogy can raise, so this commit rescues the trilogy-specific error instead. * As far as I can tell Trilogy does not raise `SocketError`, so don't bother translating that * Don't treat TRILOGY_UNEXPECTED_PACKET as a connection error. If we get this, it's probably a bug in trilogy that we should fix. I'd like to eventually get rid of TRILOGY_INVALID_SEQUENCE_ID too, but we're currently relying on it in a few tests (related to trilogy missing caching_sha2_password auth support, if I recall correctly) I'm kinda hoping we'll eventually be able to simplify this to something like: ```rb if exception.is_a?(Trilogy::ConnectionError) ConnectionFailed.new(message, connection_pool: @pool) else super end ``` but we'd need more changes to trilogy before that is possible.
This commit makes a few changes to our trilogy error translation: * trilogy-libraries/trilogy#118 introduced `Trilogy::EOFError` which we can use instead of matching on `TRILOGY_CLOSED_CONNECTION`. * trilogy-libraries/trilogy#15 introduced `Trilogy::ConnectionClosed`, which inherits from `IOError` for backwards compatibility. As far as I can tell that's the only `IOError` trilogy can raise, so this commit rescues the trilogy-specific error instead. * As far as I can tell Trilogy does not raise `SocketError`, so don't bother translating that * Don't treat TRILOGY_UNEXPECTED_PACKET as a connection error. If we get this, it's probably a bug in trilogy that we should fix. I'd like to eventually get rid of TRILOGY_INVALID_SEQUENCE_ID too, but we're currently relying on it in a few tests (related to trilogy missing caching_sha2_password auth support, if I recall correctly) I'm kinda hoping we'll eventually be able to simplify this to something like: ```rb if exception.is_a?(Trilogy::ConnectionError) ConnectionFailed.new(message, connection_pool: @pool) else super end ``` but we'd need more changes to trilogy before that is possible.
This commit makes a few changes to our trilogy error translation: * trilogy-libraries/trilogy#118 introduced `Trilogy::EOFError` which we can use instead of matching on `TRILOGY_CLOSED_CONNECTION`. * trilogy-libraries/trilogy#15 introduced `Trilogy::ConnectionClosed`, which inherits from `IOError` for backwards compatibility. As far as I can tell that's the only `IOError` trilogy can raise, so this commit rescues the trilogy-specific error instead. * As far as I can tell Trilogy does not raise `SocketError`, so don't bother translating that * Don't treat TRILOGY_UNEXPECTED_PACKET as a connection error. If we get this, it's probably a bug in trilogy that we should fix. I'd like to eventually get rid of TRILOGY_INVALID_SEQUENCE_ID too, but we're currently relying on it in a few tests (related to trilogy missing caching_sha2_password auth support, if I recall correctly) I'm kinda hoping we'll eventually be able to simplify this to something like: ```rb if exception.is_a?(Trilogy::ConnectionError) ConnectionFailed.new(message, connection_pool: @pool) else super end ``` but we'd need more changes to trilogy before that is possible.
This commit makes a few changes to our trilogy error translation: * trilogy-libraries/trilogy#118 introduced `Trilogy::EOFError` which we can use instead of matching on `TRILOGY_CLOSED_CONNECTION`. * trilogy-libraries/trilogy#15 introduced `Trilogy::ConnectionClosed`, which inherits from `IOError` for backwards compatibility. As far as I can tell that's the only `IOError` trilogy can raise, so this commit rescues the trilogy-specific error instead. * As far as I can tell Trilogy does not raise `SocketError`, so don't bother translating that * Don't treat TRILOGY_UNEXPECTED_PACKET as a connection error. If we get this, it's probably a bug in trilogy that we should fix. I'd like to eventually get rid of TRILOGY_INVALID_SEQUENCE_ID too, but we're currently relying on it in a few tests (related to trilogy missing caching_sha2_password auth support, if I recall correctly) I'm kinda hoping we'll eventually be able to simplify this to something like: ```rb if exception.is_a?(Trilogy::ConnectionError) ConnectionFailed.new(message, connection_pool: @pool) else super end ``` but we'd need more changes to trilogy before that is possible.
Fix: #11
Opening this as a draft because I hit a few roadblocks, so I figured I should solicit some feedback.
The goals are:
Trilogy::Error
.Unsolved issues (yet)
rb_syserr_fail_str
in a few places. Meaning it can still raise any of theErrno::*
errors.handle_trilogy_error
raise allTRILOGY_ERR
asProtocolError
which is aConnectionError
, butI'm not certain none of the possible errors could be considered client errors.
cc @composerinteralia @matthewd