-
Notifications
You must be signed in to change notification settings - Fork 80
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
Semian + Trilogy: Introduce adapter for Trilogy AR Adapter #468
Conversation
95793d1
to
a183f3d
Compare
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 left one comment where I think we need to change the repo.
Thank you for the great explanation on the route you chose and why, makes a lot of sense. I don't love how mysql2 and trilogy are so different here but I understand that there's not a better option right now. I know we're working on reconnects so we should revisit this implementation later on.
a183f3d
to
221bef6
Compare
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 looks good to me but let's get @Shopify/byroot and the Semian owners to review before merging.
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.
Nice, the tests read really well 🙌
lib/semian/trilogy_adapter.rb
Outdated
end | ||
|
||
def active? | ||
acquire_semian_resource(adapter: :trilogy_adapter, scope: :ping) do |
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.
Pings in the Mysql2 client are circuit broken, primarily for the flow where we're establishing a connection and we call #verify!
=> #active?
=> #ping
(more context in this PR). To mimic this at the adapter level, we should make sure #active?
is circuit broken in the same way.
I've made the scope :ping
to make it more similar to what the Semian Mysql2 adapter was doing, and since :ping
is technically the method that talks to the db, but I could change this to :active
if that makes more sense :)
a15d1cd
to
88b87a3
Compare
Hi, I am going to release next version in next few days. We can add a new adapter to the next version and release this week as well. |
88b87a3
to
951bc76
Compare
* Install adapter gem, bump to Rails edge * Introduce Trilogy Active Record adapter for Semian * Rubocop: Ignore multiple assertions per test * Add gemfiles for trilogy, CI steps, update changelog * Add test for Trilogy client default timeout
We are planning to migrate Shopify/shopify (and our other Rails applications) to the Trilogy client instead of Mysql2. This PR introduces a Semian adapter for the Trilogy Active Record adapter.
Why isn't this built at the Trilogy client layer?
Building the Semian adapter at the Trilogy lient layer is challenging because of the way Trilogy manages its connection to the server. Any time an error is encountered, Trilogy will close the connection, and automatic reconnects are not supported. This means that
TRILOGY_CONNECTION_CLOSED
errors can happen for various reasons: if the network is down, but also if some other error was encountered and the connection is no longer usable. We’d need to make non-trivial changes to Trilogy to differentiate these use cases. Targeting the AR adapter layer allows us to lean on Rails to reconnect as needed, and allows us to differentiate between true connection errors (e.g. the network is down), vs Trilogy having closed the connection itself.Why don't we write a Semian adapter that targets AbstractAdapter or AbstractMysqlAdapter?
I experimented with this here, but decided this wasn't a sensible option. Active Record translates certain errors we care about to
ActiveRecord::StatementInvalid
, and we need to look at the underlying error to see if it's something that should trigger the Semian circuit breaker (e.g. a timeout error). We'd need to bake in references to the various adapter classes (e.g.Trilogy::TimeoutError
,Mysql2::Error
), so this doesn't make sense.I've tested this adapter out with Shopify/shopify and have a passing CI build: https://buildkite.com/shopify/shopify-selective-tests/builds/969555
Feedback
Dealing with
half_open_resource_timeout
is unfortunately still a bit hacky, even at the adapter layer. If anyone has thoughts on how to do this better, I'm all ears.Basically, the Trilogy adapter forwards configs to the client, one of which is the
read_timeout
. In the context ofwith_resource_timeout
, we might be connecting to the db, in which caseconnection
is nil. Consequently, the only way I see being able to set a new (temp)read_timeout
is to mutate the@config
so that the newly instantiated client gets created with the timeout we want. If we have theconnection
already, we can reach directly to the connection (the Trilogy client) and modify theread_timeout
.In the ensure block, we restore the original timeout on the
connection
, and I'm assuming we should also reset the@config
.This is even more hacky because if no
read_timeout
is set in the config, we need to use the client's default (0), which I've hardcoded into the adapter, but could potentially change on Trilogy's end down the road...