Skip to content
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

Subclass switching #136

Merged
merged 18 commits into from
Oct 26, 2017
Merged

Subclass switching #136

merged 18 commits into from
Oct 26, 2017

Conversation

jacobat
Copy link
Contributor

@jacobat jacobat commented Oct 11, 2017

Another stab at making ARS a little more understandable. The gist of it is that we try to isolate the ActiveRecordShards logic in a class instead of monkey patching ActiveRecord::Base.

This PR changes a bunch of things around ActiveRecordShards. First up it drops support for Rails < 5. It also removes the migration parts of ARS as those can be better handled separately. It introduces a new ActiveRecordShards::ShardedModel class which sharded models must now inherit from instead of ActiveRecord::Base. On the flip side the not_sharded instruction is no longer necessary or supported. These changes should make ActiveRecord classes not inheriting from ActiveRecordShards::ShardedModel behave more like they would when not using ActiveRecordShards.

This also removes support for the default_shard idea as it doesn't make a lot of sense to talk about a default shard. If you want a random shard just use the first shard available.

Additionally this introduces the requirement that a shard must always be selected. It's no longer possible to say on_shard(nil). Only numeric shards are accepted.

Future work on this would be to separate sharding from master/slave logic and move the patches to ActiveRecord::Base down to the ActiveRecordShards::ShardedModel class making ActiveRecord::Base totally ignorant of ActiveRecordShards.

With these changes we'll need to release a new major version of ARS to comply with SemVer.

@jacobat jacobat force-pushed the jacobat/subclass-switching branch 2 times, most recently from 4ff1179 to f66c783 Compare October 11, 2017 14:34
@@ -141,8 +141,6 @@ def model.on_slave_by_default?
left_reflection.klass.on_slave_by_default?
end

# also transfer the sharded-ness of the left table to the join model
model.not_sharded unless model.left_reflection.klass.is_sharded?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will this be a problem?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure :|

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems super sketchy that we call not_sharded ... maybe this is a 1-off join model ... which means that it should now be model.sharded if foo instead ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add a test for this case?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've tried adding a test - it's not exactly obvious where to put it though

@bquorning bquorning force-pushed the jacobat/subclass-switching branch from f5f238f to c00a1b6 Compare October 11, 2017 20:04
@jacobat jacobat force-pushed the jacobat/subclass-switching branch 4 times, most recently from d011f2a to a1a1f97 Compare October 12, 2017 13:55
@jacobat jacobat mentioned this pull request Oct 12, 2017
@grosser
Copy link
Contributor

grosser commented Oct 12, 2017

I'm a little scared that an inheritance change would break all existing usages and also introduce bugs where things like base_class no longer return the right classes ... prefer an include or a sharded method

end
unless config['shard_names'].include?(options[:shard])
raise "Did not find shard #{options[:shard]} in configurations"
end
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these validations could go out as their own PR so we can test them quickly and make this PR smaller ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure we can do that.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Except that options[:shard] can still be nil which cannot be found in config['shard_names']. So the validations need to be tweaked a bit.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extracted to #143, backport to master in #144.

@pschambacher
Copy link
Contributor

That's is one big and scary PR. Should we test it on one application before merging?

@jacobat
Copy link
Contributor Author

jacobat commented Oct 12, 2017

I'm a little scared that an inheritance change would break all existing usages and also introduce bugs where things like base_class no longer return the right classes ... prefer an include or a sharded method

I considered making it a module one would extend as well. I can give it a shot. base_class should still return the right thing though as ShardedModel is an abstract class in AR terms.

This will be a new major version and will require changes to existing code so I'm not too worried about breaking existing usage.

@jacobat
Copy link
Contributor Author

jacobat commented Oct 12, 2017

That's is one big and scary PR. Should we test it on one application before merging?

I imagine releasing it as ARS 4.0 beta and test it with the K8s HC branch.

Copy link
Contributor

@pschambacher pschambacher left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 for beta tag

@jacobat jacobat force-pushed the jacobat/subclass-switching branch from a1a1f97 to bfd516d Compare October 13, 2017 09:14
@jacobat jacobat changed the base branch from master to v4 October 13, 2017 09:15
@jacobat jacobat force-pushed the jacobat/subclass-switching branch 3 times, most recently from 587958a to 9d1182c Compare October 13, 2017 09:34
@jacobat jacobat force-pushed the jacobat/subclass-switching branch 2 times, most recently from 9746156 to 9d1182c Compare October 23, 2017 09:42
class ShardedModel < ActiveRecord::Base
self.abstract_class = true

extend ActiveRecordShards::Ext::ShardedModel
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this better than def self.is_sharded? ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean why am I extending a module over just defining a method?

Copy link
Member

@bquorning bquorning Oct 23, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that’s what I meant.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I need the module to extend into various ActiveRecord classes where I can't easily change the superclass (models from gems). As I need a module I might as well reuse the module here to keep it slightly more dry.

@jacobat jacobat force-pushed the jacobat/subclass-switching branch from edf44fd to 268e74d Compare October 24, 2017 10:43
current_shard_selection.shard = options[:shard]
end

if options.key?(:slave)
current_shard_selection.on_slave = options[:slave]
Copy link
Member

@bquorning bquorning Oct 25, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do/should we support master/slave switching without switching shards?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure what you're getting at?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Me neither. This is fine.

ActiveSupport::Deprecation.warn("Calling not_sharded is deprecated. "\
"Please ensure to still read from the "\
"account db slave after removing the "\
"call.")
end

def is_sharded? # rubocop:disable Naming/PredicateName
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we seize the moment and rename .is_sharded? to .sharded??

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope ;)

Copy link
Member

@bquorning bquorning left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few comments but 👍 and ❤️ to the overall plan.

@grosser
Copy link
Contributor

grosser commented Oct 25, 2017 via email

@jacobat
Copy link
Contributor Author

jacobat commented Oct 25, 2017

I'm not sure what you're saying?

@bquorning
Copy link
Member

I think it’s a threading fail. The reveals my original question

Should we seize the moment and rename .is_sharded? to .sharded??

@jacobat
Copy link
Contributor Author

jacobat commented Oct 25, 2017

Ah!

jacobat and others added 18 commits October 26, 2017 10:56
It does not make sense to have a default shard so we're removing this
We don't want to have a "selection" where nothing is selected as that may cause
weird issues. For instance it may result in not being able to get the schema of
sharded tables.
If we're using ARS we expect shards to be configured. We don't want to silently
fail in case the configuration is missing.
If we're missing configuration we raise an exception at the point we discover
the missing configuration. This is to avoid accidentally calling .shard= with
nil.
We move the state manipulating on_slave= call to after we check that we're
actually able to perform the shard switch. Otherwise we may accidentally update
state and then see an exception leaving us in an inconsistent state.
When selecting a new shard the user should always select an actual shard. It
does not make sense to select NO_SHARD.
When we ask for the shard we must ensure that we do have a shard selected.
It no longer makes sense to talk about being able to switch to shard and back
as unsharded models will now always be unsharded and sharded models will now
always be sharded.
I don't even know why we're testing behaviour of ARS in an unsharded
environment.
From now on sharded models must inherit from ActiveRecordShards::ShardedModel
- and no longer will users need to use the "not_sharded" instruction to mark
models not sharded.

By doing this we've simplified the logic around sharding as
ActiveRecord::Base no longer needs to be part of the calculation around
wether a class is sharded or not. It's now purely defined in terms of
inheritance, inheriting from ShardedModel means the model is sharded.
This is no longer used
We are method chaining not_sharded in ZendeskDatabaseSupport and adding default
reading from the slave for unsharded models. To help the transition we'll keep
the not_sharded method around until we can remove it from the dependents.
Instead of checking class inheritance we can just call a class method. This way
we can define it to be false for ActiveRecord::Base and override it in sharded
subclasses. This also gives us the possibility of using a module (or just plain
defining the method in any random class).
Global state in tests, yay
@jacobat jacobat force-pushed the jacobat/subclass-switching branch from 4b0a309 to db1760d Compare October 26, 2017 09:02
@jacobat jacobat merged commit 2a27966 into v4 Oct 26, 2017
@jacobat jacobat deleted the jacobat/subclass-switching branch October 26, 2017 09:18
@jacobat
Copy link
Contributor Author

jacobat commented Oct 26, 2017

I've merged #146 bumping to beta-4.0.0.beta1 on the v4 branch. Does anyone know how to release this onto rubygems.org?

@bquorning
Copy link
Member

v4.0.0.beta1 has been released 🎉 ✨

@bquorning bquorning added this to the v4 milestone Dec 20, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants