module MixedGauge::Model::ClassMethods
Public Instance Methods
Returns all generated shard model class. Useful to query to all shards. @return [Array<Class>] An array of shard models @example
User.all_shards.flat_map {|m| m.find_by(name: 'alice') }.compact
# File lib/mixed_gauge/model.rb, line 128 def all_shards shard_repository.all end
@return [Mixedgauge::AllShardsInParallel] @example
User.all_shards_in_parallel.map {|m| m.where.find_by(name: 'Alice') }.compact
# File lib/mixed_gauge/model.rb, line 135 def all_shards_in_parallel AllShardsInParallel.new(all_shards, service: service) end
Register hook to assign auto-generated distkey or something. Sometimes you want to generates distkey value before validation. Since mixed_gauge generates sub class of your models, AR's callback is not usesless for this usecase, so mixed_gauge offers its own callback method. @example
class User include MixedGauge::Model use_cluster :user def_distkey :name before_put do |attributes| attributes[:name] = generate_name unless attributes[:name] end end
# File lib/mixed_gauge/model.rb, line 111 def before_put(&block) @before_put_callback = block end
Distkey is a column. mixed_gauge hashes that value and determine which shard to store. @param [Symbol] column
# File lib/mixed_gauge/model.rb, line 53 def def_distkey(column) self.distkey = column.to_sym end
Returns nil when not found. Except that, is same as `.get!`. @param [String] key @return [ActiveRecord::Base, nil] A shard model instance
# File lib/mixed_gauge/model.rb, line 83 def get(key) raise 'key must be a String' unless key.is_a?(String) shard_for(key.to_s).find_by(distkey => key) end
`.get!` raises MixedGauge::RecordNotFound
which is child class of `ActiveRecord::RecordNotFound` so you can rescue that exception as same as AR's RecordNotFound
. @param [String] key @return [ActiveRecord::Base] A shard model instance @raise [MixedGauge::RecordNotFound]
# File lib/mixed_gauge/model.rb, line 94 def get!(key) get(key) || raise(MixedGauge::RecordNotFound) end
Define utility methods which uses all shards or specific shard. These methods can be called from included model class. @example
class User include MixedGauge::Model use_cluster :user def_distkey :name parent_methods do def all_count parallel.map {|m| m.count }.reduce(&:+) end def find_from_all_by(condition) parallel.flat_map {|m m.find_by(condition) }.compact.first end end end User.put!(email: 'a@m.com', name: 'a') User.put!(email: 'b@m.com', name: 'b') User.all_count #=> 2 User.find_from_all_by(name: 'b') #=> User b
# File lib/mixed_gauge/model.rb, line 177 def parent_methods(&block) instance_eval(&block) end
Create new record with given attributes in proper shard for given key. When distkey value is empty, raises MixedGauge::MissingDistkeyAttribute
error. @param [Hash] attributes @return [ActiveRecord::Base] A shard model instance @raise [MixedGauge::MissingDistkeyAttribute]
# File lib/mixed_gauge/model.rb, line 69 def put!(attributes) raise '`distkey` is not defined. Use `def_distkey`.' unless distkey @before_put_callback.call(attributes) if @before_put_callback if (key = attributes[distkey]) || attributes[distkey.to_s] shard_for(key).create!(attributes) else raise MixedGauge::MissingDistkeyAttribute end end
@param [Hash{Symbol => Symbol}] mapping A pairs of role name and
AR model class name.
# File lib/mixed_gauge/model.rb, line 59 def replicates_with(mapping) self.replication_mapping = MixedGauge::ReplicationMapping.new(mapping) end
Returns a generated model class of included model class which has proper connection config for the shard for given key. @param [String] key A value of distkey @return [Class] A generated model class for given distkey value
# File lib/mixed_gauge/model.rb, line 119 def shard_for(key) connection_name = cluster_routing.route(key.to_s) shard_repository.fetch(connection_name) end
See example definitions in `spec/models.rb`. @param [Symbol] A role name of target cluster. @return [Class, Object] if block given then yielded result else
target shard model.
@example
UserReadonly.all_shards.each do |m| target_ids = m.where(age: 1).pluck(:id) m.switch(:master) do |master| master.where(id: target_ids).delete_all end end
# File lib/mixed_gauge/model.rb, line 151 def switch(role_name, &block) replication_mapping.switch(self, role_name, &block) end
The cluster config must be defined before `use_cluster`. @param [Symbol] name A cluster name which is set by MixedGauge.configure
# File lib/mixed_gauge/model.rb, line 34 def use_cluster(name, thread_pool_size_base: 3) config = MixedGauge.config.fetch_cluster_config(name) self.cluster_routing = MixedGauge::Routing.new(config) self.shard_repository = MixedGauge::ShardRepository.new(config, self) thread_size = (shard_repository.all.size * thread_pool_size_base) self.service = Expeditor::Service.new( executor: Concurrent::ThreadPoolExecutor.new( min_threads: thread_size, max_threads: thread_size, max_queue: shard_repository.all.size, fallback_policy: :abort ) ) self.abstract_class = true end