-
Notifications
You must be signed in to change notification settings - Fork 22k
Support integer shard keys #55680
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
Support integer shard keys #55680
Conversation
47ac6ee
to
482a235
Compare
Agreed. Integer based shards are very common / useful. @eileencodes any objections? |
|
||
IntegerKeysBase.connects_to(shards: { | ||
default: { writing: :primary, reading: :primary }, | ||
1 => { writing: :primary_shard_one, reading: :primary_shard_one_replica } |
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 have a problem with this fundamentally however...this is going to sound picky and but seeing it written out it's kind of ugly, especially mixing symbols and integers like default:
with 1 =>
.
Here's my thought process:
So should 0
be default also so we're not mixing symbols and integers? Or should we not accept this apps generate a key name like shard_1
and then in the connects to it's connected_to(shard: "shard_#{account.shard}")
? My issue is how with this change we're encouraging the mixing of symbols and integers and making the API potentially very ugly.
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 agree that it was pretty ugly. 🤮
I've updated the test to first call:
ActiveRecord::Base.default_shard = 0
It's normally :default
, which necessitated mixing :default
in with the integers. I imagine if folks are only using integers to identify shards then they would pick a one as a default shard and configure ActiveRecord::Base
accordingly (or just use a separate abstract class).
I'd just like to avoid coercing the integer into a string and then into a symbol, but I also recognize I'm bumping into a Ruby constraint 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.
So should
0
be default also so we're not mixing symbols and integers?
I don't think 0
should be considered a default. If anything, with numeric shards you want no default at all (enforce that one shard is always selected).
Or should we not accept this apps generate a key name like shard_1
This is what Shopify's monolith was doing, and I remember at one point the "shard_#{shard_id}"
interpolation was the number one allocation source, so we had to add some cache and memoization etc.
Overall I like the purely numeric naming, it's practical.
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 0 should be considered a default. If anything, with numeric shards you want no default at all (enforce that one shard is always selected).
I agree. The other tests in the file were covering what happens when there is a default so I opted to cover that case. Happy to make changes though.
This is what Shopify's monolith was doing, and I remember at one point the "shard_#{shard_id}" interpolation was the number one allocation source, so we had to add some cache and memoization etc.
Yep, we're in a similar situation at Zendesk.
482a235
to
d795e8a
Compare
Currently, `.connects_to(shards: ...)` coerces all of the shard keys into symbols. Because an integer cannot be coerced into a symbol, attempting to identify a shard with an integer will raise an exception: ```ruby 1.to_sym (irb):1:in '<main>': undefined method 'to_sym' for an instance of Integer (NoMethodError) ``` I think it would be useful to support integers as shard keys along with symbols. This would simplify shard switching when shards are identified by integer columns in a database. As an example, if there is an `accounts` table with a `shard` integer column which identifies which shard that account's data lives on, this currently would not work: ```ruby account = Account.first ActiveRecord::Base.connected_to(shard: account.shard) do # Raises NoMethodError end ``` A workaround would be to first coerce or serialize the integer into a string but that's unideal: ```ruby account = Account.first ActiveRecord::Base.connected_to(shard: account.shard.to_s.to_sym) do # ... end ``` This makes a `.connects_to` change, coercing the shard key into a symbol _unless_ the key is an integer. From there, passing a symbol or integer to `connected_to(shard: ...)` should both work. In the test, we call: ```ruby ActiveRecord::Base.default_shard = 0 ``` Normally, it would be `:default`. In that case we'd have to mix symbols and integers in the `.connects_to:(shards:)` hash which is pretty ugly.
d795e8a
to
106d5c5
Compare
Motivation / Background
Currently,
.connects_to(shards: ...)
coerces all of the shard keys into symbols. Because an integer cannot be coerced into a symbol, attempting to identify a shard with an integer will raise an exception:I think it would be useful to support integers as shard keys along with symbols. This would simplify shard switching when shards are identified by integer columns in a database.
As an example, if there is an
accounts
table with ashard
integer column which identifies which shard that account's data lives on, this currently would not work:A workaround would be to first coerce or serialize the integer into a string but that's unideal:
Detail
This makes a
.connects_to
change, coercing the shard key into a symbol unless the key is an integer. From there, passing a symbol or integer toconnected_to(shard: ...)
should both work.Additional information
connected_to
will no longer raiseNoMethodError
when you pass it shard keys as integers.Checklist
Before submitting the PR make sure the following are checked:
[Fix #issue-number]