shard_handler 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c2728db474dde6a413de4340acebf59e340bd929
4
+ data.tar.gz: f4c4df74df1ea909359edf2f8f79fff624824090
5
+ SHA512:
6
+ metadata.gz: bac3f0308f32e0aee8f1ddd1e9e196b06902041158db7567f206435b549e58a944894ef21176007d4871b238175bf9b6cbffbbd6386781e72511e3933010296c
7
+ data.tar.gz: e90d66071b5e082ae1e09c071e204d74adc0b8b033f71715e27d1972ee277836c60c8c961fbf67833044bf7ea605f2d74f29ae0eb6788ca44257fb785762862f
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ /spec/database.yml
11
+ /spec/shards.yml
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1.3
4
+ before_install: gem install bundler -v 1.10.5
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in shard_handler.gemspec
4
+ gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Locaweb
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,65 @@
1
+ # ShardHandler
2
+
3
+ This gem is a simple sharding solution for Rails applications. It was created
4
+ to be used in multitenant applications, when data is shared across multiple
5
+ databases but accessed through the same ActiveRecord model.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'shard_handler'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install shard_handler
22
+
23
+ ## Usage
24
+
25
+ All models that need sharding must inherit from `ShardHandler::Model`. For
26
+ example:
27
+
28
+ ```ruby
29
+ class Post < ShardHandler::Model
30
+ end
31
+ ```
32
+
33
+ Before executing any query, you must switch to the appropriate shard:
34
+
35
+ ```ruby
36
+ ShardHandler.current_shard = :shard1
37
+ puts Post.pluck(:title)
38
+
39
+ # or
40
+
41
+ ShardHandler.using(:shard1) do
42
+ puts Post.pluck(:title)
43
+ end
44
+ ```
45
+
46
+ ## Development
47
+
48
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run
49
+ `rake test` to run the tests. You can also run `bin/console` for an interactive
50
+ prompt that will allow you to experiment.
51
+
52
+ To install this gem onto your local machine, run `bundle exec rake install`. To
53
+ release a new version, update the version number in `version.rb`, and then run
54
+ `bundle exec rake release`, which will create a git tag for the version, push
55
+ git commits and tags, and push the `.gem` file to
56
+ [rubygems.org](https://rubygems.org).
57
+
58
+ ## Contributing
59
+
60
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/shard_handler.
61
+
62
+
63
+ ## License
64
+
65
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
@@ -0,0 +1,10 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << 'test'
6
+ t.libs << 'lib'
7
+ t.test_files = FileList['test/**/*_test.rb']
8
+ end
9
+
10
+ task default: :test
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'shard_handler'
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require 'irb'
14
+ IRB.start
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,8 @@
1
+ require 'shard_handler/version'
2
+ require 'shard_handler/model'
3
+ require 'shard_handler/handler'
4
+ require 'shard_handler/thread_registry'
5
+ require 'shard_handler/errors'
6
+
7
+ module ShardHandler
8
+ end
@@ -0,0 +1,9 @@
1
+ module ShardHandler
2
+ # This error is raised when one tries to perform a query on {Model} without
3
+ # setting it up first.
4
+ class SetupError < StandardError; end
5
+
6
+ # This error is raised when using a shard name that does not exist in the
7
+ # configuration.
8
+ class UnknownShardError < StandardError; end
9
+ end
@@ -0,0 +1,49 @@
1
+ module ShardHandler
2
+ # Handles which {ConnectionHandler} instance should be used based on the
3
+ # shard name that is set for the Thread. Each {Model} class has its own
4
+ # {Handler}.
5
+ #
6
+ # @see Model
7
+ # @api private
8
+ class Handler
9
+ # @param klass [ActiveRecord::Base] model class
10
+ # @param configs [Hash] a hash with database connection settings
11
+ def initialize(klass, configs)
12
+ @klass = klass
13
+ @configs = configs
14
+ @cache = {}
15
+ end
16
+
17
+ # Creates a {ConnectionHandler} instance for each configured shard and puts
18
+ # it on cache to be used later by {#connection_handler_for}.
19
+ def setup
20
+ resolver = ActiveRecord::ConnectionAdapters::ConnectionSpecification::Resolver.new(@configs)
21
+
22
+ @configs.each do |name, _|
23
+ name = name.to_sym
24
+
25
+ connection_handler = ActiveRecord::ConnectionAdapters::ConnectionHandler.new
26
+ connection_handler.establish_connection(@klass, resolver.spec(name))
27
+
28
+ @cache[name] = connection_handler
29
+ end
30
+ end
31
+
32
+ # Returns the appropriate ConnectionHandler instance for the given shard
33
+ # name.
34
+ #
35
+ # @param name [Symbol, String] shard name
36
+ # @return [ActiveRecord::ConnectionAdapters::ConnectionHandler]
37
+ def connection_handler_for(name)
38
+ return if name.nil?
39
+ @cache.fetch(name.to_sym) do
40
+ fail UnknownShardError, "#{name.inspect} is not a valid shard name"
41
+ end
42
+ end
43
+
44
+ # Disconnects from all shards.
45
+ def disconnect_all
46
+ @cache.values.map(&:clear_all_connections!)
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,88 @@
1
+ require 'active_record'
2
+
3
+ module ShardHandler
4
+ # This is an abstract model that adds sharding capabilities on ActiveRecord.
5
+ # When you need to query different shards using the same model, you must
6
+ # inherit from this class and configure it.
7
+ #
8
+ # @example
9
+ # class Post < ShardHandler::Model
10
+ # end
11
+ #
12
+ # Post.setup({
13
+ # 'shard1' => {
14
+ # 'adapter' => 'postgresql',
15
+ # 'database' => 'shard_handler_development',
16
+ # 'username' => 'postgres',
17
+ # 'password' => ''
18
+ # }
19
+ # })
20
+ #
21
+ # Post.using(:shard1) do
22
+ # Post.update_all(title: 'foo')
23
+ # end
24
+ class Model < ActiveRecord::Base
25
+ self.abstract_class = true
26
+
27
+ class << self
28
+ # @api private
29
+ # @return [Handler]
30
+ def handler
31
+ @@handler
32
+ end
33
+
34
+ # This method creates an instance of {Handler} for this class. This method
35
+ # must be called before performing any query on shards.
36
+ #
37
+ # @param config [Hash] a hash with database connection settings
38
+ def setup(config)
39
+ @@handler = Handler.new(self, config)
40
+ @@handler.setup
41
+ end
42
+
43
+ # Returns the current shard name for the current Thread.
44
+ #
45
+ # @return [Symbol]
46
+ def current_shard
47
+ ThreadRegistry.current_shard
48
+ end
49
+
50
+ # Sets the current shard name for the current Thread.
51
+ #
52
+ # @param name [Symbol, String] shard name configured using {.setup}
53
+ def current_shard=(name)
54
+ ThreadRegistry.current_shard = name.nil? ? nil : name.to_sym
55
+ end
56
+
57
+ # Overrides ActiveRecord::Core#connection_handler method to return the
58
+ # appropriate ConnectionHandler for the current shard. This is the
59
+ # integration point between ActiveRecord and this gem.
60
+ #
61
+ # @api private
62
+ # @return (see Handler#connection_handler_for)
63
+ def connection_handler
64
+ fail(SetupError, 'the model was not setup') unless @@handler
65
+ @@handler.connection_handler_for(current_shard) || super
66
+ end
67
+
68
+ # This method will switch to the passed shard making all queries be
69
+ # executed using the shard connection.
70
+ #
71
+ # @param shard [Symbol, String] shard name configured using .setup
72
+ # @yield The block that must be executed using the shard connection
73
+ def using(shard)
74
+ old_shard = current_shard
75
+ self.current_shard = shard
76
+ yield
77
+ ensure
78
+ # Returns any connections in use by the current thread back to the pool.
79
+ # It must be executed before changing the shard name back to its
80
+ # old value.
81
+ self.clear_active_connections!
82
+ self.current_shard = old_shard
83
+ end
84
+
85
+ private :establish_connection
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,15 @@
1
+ require 'active_support/per_thread_registry'
2
+
3
+ module ShardHandler
4
+ # This class is used as a registry for the shard name that is being used in
5
+ # the current thread. Because ActiveRecord's connections are global in the
6
+ # thread scope, we need to make sure that the shard name is change only for
7
+ # the current thread and not on process or other threads.
8
+ #
9
+ # @see ActiveSupport::PerThreadRegistry
10
+ # @api private
11
+ class ThreadRegistry
12
+ extend ActiveSupport::PerThreadRegistry
13
+ attr_accessor :current_shard
14
+ end
15
+ end
@@ -0,0 +1,3 @@
1
+ module ShardHandler
2
+ VERSION = '0.1.3'
3
+ end
@@ -0,0 +1,31 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'shard_handler/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'shard_handler'
8
+ spec.version = ShardHandler::VERSION
9
+ spec.authors = ['Lenon Marcel', 'Rafael Timbó', 'Lucas Nogueira',
10
+ 'Rodolfo Liviero']
11
+ spec.email = ['lenon.marcel@gmail.com', 'rafaeltimbosoares@gmail.com',
12
+ 'lukspn.27@gmail.com', 'rodolfoliviero@gmail.com']
13
+ spec.summary = 'This gem is a simple sharding solution for Rails applications'
14
+ spec.description = 'This gem is a simple sharding solution for Rails applications'
15
+ spec.homepage = 'https://github.com/locaweb/shard_handler'
16
+ spec.license = 'MIT'
17
+
18
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
19
+ spec.bindir = 'exe'
20
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
+ spec.require_paths = ['lib']
22
+
23
+ spec.add_dependency 'activerecord', '~> 4.2.0'
24
+ spec.add_dependency 'activesupport', '~> 4.2.0'
25
+
26
+ spec.add_development_dependency 'bundler', '~> 1.10'
27
+ spec.add_development_dependency 'rake', '~> 10.0'
28
+ spec.add_development_dependency 'rspec'
29
+ spec.add_development_dependency 'pg'
30
+ spec.add_development_dependency 'yard'
31
+ end
metadata ADDED
@@ -0,0 +1,165 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: shard_handler
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.3
5
+ platform: ruby
6
+ authors:
7
+ - Lenon Marcel
8
+ - Rafael Timbó
9
+ - Lucas Nogueira
10
+ - Rodolfo Liviero
11
+ autorequire:
12
+ bindir: exe
13
+ cert_chain: []
14
+ date: 2015-07-30 00:00:00.000000000 Z
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: activerecord
18
+ requirement: !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - "~>"
21
+ - !ruby/object:Gem::Version
22
+ version: 4.2.0
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: 4.2.0
30
+ - !ruby/object:Gem::Dependency
31
+ name: activesupport
32
+ requirement: !ruby/object:Gem::Requirement
33
+ requirements:
34
+ - - "~>"
35
+ - !ruby/object:Gem::Version
36
+ version: 4.2.0
37
+ type: :runtime
38
+ prerelease: false
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - "~>"
42
+ - !ruby/object:Gem::Version
43
+ version: 4.2.0
44
+ - !ruby/object:Gem::Dependency
45
+ name: bundler
46
+ requirement: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - "~>"
49
+ - !ruby/object:Gem::Version
50
+ version: '1.10'
51
+ type: :development
52
+ prerelease: false
53
+ version_requirements: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - "~>"
56
+ - !ruby/object:Gem::Version
57
+ version: '1.10'
58
+ - !ruby/object:Gem::Dependency
59
+ name: rake
60
+ requirement: !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - "~>"
63
+ - !ruby/object:Gem::Version
64
+ version: '10.0'
65
+ type: :development
66
+ prerelease: false
67
+ version_requirements: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - "~>"
70
+ - !ruby/object:Gem::Version
71
+ version: '10.0'
72
+ - !ruby/object:Gem::Dependency
73
+ name: rspec
74
+ requirement: !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
79
+ type: :development
80
+ prerelease: false
81
+ version_requirements: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ - !ruby/object:Gem::Dependency
87
+ name: pg
88
+ requirement: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
93
+ type: :development
94
+ prerelease: false
95
+ version_requirements: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ version: '0'
100
+ - !ruby/object:Gem::Dependency
101
+ name: yard
102
+ requirement: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ type: :development
108
+ prerelease: false
109
+ version_requirements: !ruby/object:Gem::Requirement
110
+ requirements:
111
+ - - ">="
112
+ - !ruby/object:Gem::Version
113
+ version: '0'
114
+ description: This gem is a simple sharding solution for Rails applications
115
+ email:
116
+ - lenon.marcel@gmail.com
117
+ - rafaeltimbosoares@gmail.com
118
+ - lukspn.27@gmail.com
119
+ - rodolfoliviero@gmail.com
120
+ executables: []
121
+ extensions: []
122
+ extra_rdoc_files: []
123
+ files:
124
+ - ".gitignore"
125
+ - ".rspec"
126
+ - ".travis.yml"
127
+ - Gemfile
128
+ - LICENSE.txt
129
+ - README.md
130
+ - Rakefile
131
+ - bin/console
132
+ - bin/setup
133
+ - lib/shard_handler.rb
134
+ - lib/shard_handler/errors.rb
135
+ - lib/shard_handler/handler.rb
136
+ - lib/shard_handler/model.rb
137
+ - lib/shard_handler/thread_registry.rb
138
+ - lib/shard_handler/version.rb
139
+ - shard_handler.gemspec
140
+ homepage: https://github.com/locaweb/shard_handler
141
+ licenses:
142
+ - MIT
143
+ metadata: {}
144
+ post_install_message:
145
+ rdoc_options: []
146
+ require_paths:
147
+ - lib
148
+ required_ruby_version: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ required_rubygems_version: !ruby/object:Gem::Requirement
154
+ requirements:
155
+ - - ">="
156
+ - !ruby/object:Gem::Version
157
+ version: '0'
158
+ requirements: []
159
+ rubyforge_project:
160
+ rubygems_version: 2.4.6
161
+ signing_key:
162
+ specification_version: 4
163
+ summary: This gem is a simple sharding solution for Rails applications
164
+ test_files: []
165
+ has_rdoc: