switchman-inst-jobs 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 5cc218f034bd73745f6e3baf68bfd2a582deac1e
4
+ data.tar.gz: 1360f305062ef01a6142da72e9e0703db33ef8dc
5
+ SHA512:
6
+ metadata.gz: 428cf01ae0ade7147f4f574f766003fd6be59bf6d353d469ee56111c379ff3ea3f6ef25dd8b3644770776f5b8f1f1ba9b03fb82cfa812076e05f6435bcaf91fb
7
+ data.tar.gz: d12f3089fadf8bc28d4c86b5548badfc47de993e20353afb21e738d456031e852b92be9f5b280bcc15b938c3a3d157de0508f2ad0f52292d333464e44f319410
@@ -0,0 +1,33 @@
1
+ class AddShardIdToDelayedJobs < ActiveRecord::Migration
2
+ disable_ddl_transaction!
3
+
4
+ def connection
5
+ Delayed::Backend::ActiveRecord::Job.connection
6
+ end
7
+
8
+ def up
9
+ add_column :delayed_jobs, :shard_id, :integer, limit: 8
10
+ add_index :delayed_jobs, :shard_id, algorithm: :concurrently
11
+
12
+ add_column :failed_jobs, :shard_id, :integer, limit: 8
13
+ add_index :failed_jobs, :shard_id, algorithm: :concurrently
14
+
15
+ add_column :switchman_shards, :delayed_jobs_shard_id, :integer, limit: 8
16
+ add_foreign_key(
17
+ :switchman_shards,
18
+ :switchman_shards,
19
+ column: :delayed_jobs_shard_id
20
+ )
21
+ end
22
+
23
+ def down
24
+ remove_foreign_key :switchman_shards, column: :delayed_jobs_shard_id
25
+ remove_column :switchman_shards, :delayed_jobs_shard_id
26
+
27
+ remove_index :failed_jobs, :shard_id
28
+ remove_column :failed_jobs, :shard_id
29
+
30
+ remove_index :delayed_jobs, :shard_id
31
+ remove_column :delayed_jobs, :shard_id
32
+ end
33
+ end
@@ -0,0 +1,46 @@
1
+ require 'inst-jobs'
2
+ require 'rails/railtie'
3
+ require 'switchman'
4
+
5
+ module SwitchmanInstJobs
6
+ def self.initialize_active_record
7
+ ::ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.prepend(
8
+ ActiveRecord::ConnectionAdapters::PostgreSQLAdapter
9
+ )
10
+ end
11
+
12
+ def self.initialize_inst_jobs
13
+ ::Delayed::Backend::ActiveRecord::Job.prepend(
14
+ Delayed::Backend::Base
15
+ )
16
+ ::Delayed::Backend::Redis::Job.prepend(
17
+ Delayed::Backend::Base
18
+ )
19
+ ::Delayed::Backend::Redis::Job.column :shard_id, :integer
20
+ ::Delayed::Pool.prepend Delayed::Pool
21
+ ::Delayed::Worker.prepend Delayed::Worker
22
+ ::Object.include Delayed::MessageSending
23
+ end
24
+
25
+ def self.initialize_shackles
26
+ ::Shackles.singleton_class.prepend Shackles::ClassMethods
27
+ end
28
+
29
+ def self.initialize_switchman
30
+ ::Switchman::DatabaseServer.prepend Switchman::DatabaseServer
31
+ ::Switchman::DefaultShard.prepend Switchman::DefaultShard
32
+ ::Switchman::Shard.prepend Switchman::Shard
33
+ end
34
+ end
35
+
36
+ require 'switchman_inst_jobs/active_record/connection_adapters/postgresql_adapter'
37
+ require 'switchman_inst_jobs/active_record/migration'
38
+ require 'switchman_inst_jobs/delayed/backend/base'
39
+ require 'switchman_inst_jobs/delayed/message_sending'
40
+ require 'switchman_inst_jobs/delayed/pool'
41
+ require 'switchman_inst_jobs/delayed/worker'
42
+ require 'switchman_inst_jobs/railtie'
43
+ require 'switchman_inst_jobs/shackles'
44
+ require 'switchman_inst_jobs/switchman/database_server'
45
+ require 'switchman_inst_jobs/switchman/default_shard'
46
+ require 'switchman_inst_jobs/switchman/shard'
@@ -0,0 +1,14 @@
1
+ module SwitchmanInstJobs
2
+ module ActiveRecord
3
+ module ConnectionAdapters
4
+ module PostgreSQLAdapter
5
+ def set_search_path(function, args = '()', path = ::Switchman::Shard.current.name)
6
+ execute <<-SQL
7
+ ALTER FUNCTION #{quote_table_name(function)}#{args}
8
+ SET search_path TO #{path}
9
+ SQL
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,27 @@
1
+ module SwitchmanInstJobs
2
+ module ActiveRecord
3
+ module Migration
4
+ module ClassMethods
5
+ def self.included(klass)
6
+ klass.send(:attr_writer, :open_migrations)
7
+ end
8
+
9
+ def open_migrations
10
+ @open_migrations ||= 0
11
+ end
12
+ end
13
+
14
+ def migrate(direction)
15
+ ::ActiveRecord::Migration.open_migrations += 1
16
+ super
17
+ ensure
18
+ ::ActiveRecord::Migration.open_migrations -= 1
19
+ end
20
+ end
21
+ end
22
+ end
23
+
24
+ ActiveRecord::Migration.prepend SwitchmanInstJobs::ActiveRecord::Migration
25
+ ActiveRecord::Migration.singleton_class.include(
26
+ SwitchmanInstJobs::ActiveRecord::Migration::ClassMethods
27
+ )
@@ -0,0 +1,54 @@
1
+ module SwitchmanInstJobs
2
+ module Delayed
3
+ module Backend
4
+ module Base
5
+ module ClassMethods
6
+ def enqueue(object, options = {})
7
+ enqueue_options = options.merge(
8
+ current_shard: ::Switchman::Shard.current
9
+ )
10
+
11
+ if ::ActiveRecord::Migration.open_migrations.positive?
12
+ ::Switchman::Shard.current.delayed_jobs_shard.activate(:delayed_jobs) do
13
+ super(object, enqueue_options)
14
+ end
15
+ else
16
+ super(object, enqueue_options)
17
+ end
18
+ end
19
+ end
20
+
21
+ def self.prepended(base)
22
+ base.singleton_class.prepend(ClassMethods)
23
+ base.shard_category = :delayed_jobs if base.name == 'Delayed::Backend::ActiveRecord::Job'
24
+ end
25
+
26
+ def current_shard
27
+ @current_shard ||= ::Switchman::Shard.lookup(shard_id)
28
+ end
29
+
30
+ def current_shard=(shard)
31
+ self.shard_id = shard.id
32
+ self.shard_id = nil if shard.is_a?(::Switchman::DefaultShard)
33
+ end
34
+
35
+ def invoke_job
36
+ current_shard.activate { super }
37
+ end
38
+
39
+ def deserialize(source)
40
+ raise "Shard not found: #{shard_id}" unless current_shard
41
+ current_shard.activate { super }
42
+ rescue ::Switchman::ConnectionError, PG::ConnectionBad, PG::UndefinedTable
43
+ # likely a missing shard with a stale cache
44
+ current_shard.send(:clear_cache)
45
+ ::Switchman::Shard.clear_cache
46
+ unless ::Switchman::Shard.where(id: shard_id).exists?
47
+ raise "Shard not found: #{shard_id}"
48
+ end
49
+ raise
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,10 @@
1
+ module SwitchmanInstJobs
2
+ module Delayed
3
+ module MessageSending
4
+ def send_later_enqueue_args(method, _enqueue_args = {}, *args)
5
+ return send(method, *args) if ::Switchman::DatabaseServer.creating_new_shard
6
+ super
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,29 @@
1
+ module SwitchmanInstJobs
2
+ module Delayed
3
+ module Pool
4
+ def unlock_orphaned_jobs(worker = nil, pid = nil)
5
+ if worker
6
+ shards = [worker.shard]
7
+ else
8
+ # Since we're not unlocking for a specific worker, look through
9
+ # the config for all shards this pool has workers for, and unlock
10
+ # on each shard found.
11
+ #
12
+ # If this host used to have workers for shard X, and then it died
13
+ # ungracefully at the same time that all workers for shard X were
14
+ # removed, we won't properly unlock those jobs here. That's an
15
+ # acceptable edge case though.
16
+ #
17
+ # We purposely don't .compact to remove nils here, since if any
18
+ # workers are on the default jobs shard we want to unlock against
19
+ # that shard too.
20
+ shard_ids = @config[:workers].map { |c| c[:shard] }.uniq
21
+ shards = shard_ids.map { |shard_id| ::Delayed::Worker.shard(shard_id) }
22
+ end
23
+ ::Switchman::Shard.with_each_shard(shards, [:delayed_jobs]) do
24
+ super
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,34 @@
1
+ module SwitchmanInstJobs
2
+ module Delayed
3
+ module Worker
4
+ def self.prepended(base)
5
+ base.singleton_class.prepend(ClassMethods)
6
+ end
7
+
8
+ def start
9
+ shard.activate(:delayed_jobs) { super }
10
+ end
11
+
12
+ # Worker#run is usually only called from Worker#start, but if the worker
13
+ # is called directly from the console, we want to make sure it still gets
14
+ # the right shard activated.
15
+ def run
16
+ shard.activate(:delayed_jobs) { super }
17
+ end
18
+
19
+ def shard
20
+ self.class.shard(@config[:shard])
21
+ end
22
+
23
+ module ClassMethods
24
+ def shard(shard_id)
25
+ if shard_id
26
+ shard = ::Switchman::Shard.lookup(shard_id)
27
+ return shard if shard
28
+ end
29
+ ::Switchman::Shard.default.delayed_jobs_shard
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,25 @@
1
+ module SwitchmanInstJobs
2
+ class Railtie < Rails::Railtie
3
+ initializer 'sharding.active_record',
4
+ after: 'switchman.extend_connection_adapters' do
5
+ SwitchmanInstJobs.initialize_active_record
6
+ end
7
+
8
+ initializer 'sharding.delayed' do
9
+ SwitchmanInstJobs.initialize_inst_jobs
10
+ end
11
+
12
+ initializer 'sharding.shackles',
13
+ after: 'switchman.extend_shackles' do
14
+ SwitchmanInstJobs.initialize_shackles
15
+ end
16
+
17
+ initializer 'sharding.switchman' do
18
+ SwitchmanInstJobs.initialize_switchman
19
+ end
20
+
21
+ config.after_initialize do
22
+ ::Switchman::Shard.default.delayed_jobs_shard.activate!(:delayed_jobs)
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,13 @@
1
+ module SwitchmanInstJobs
2
+ module Shackles
3
+ module ClassMethods
4
+ def activate(env, &block)
5
+ if ::ActiveRecord::Migration.open_migrations.positive?
6
+ yield
7
+ else
8
+ super
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,16 @@
1
+ module SwitchmanInstJobs
2
+ module Switchman
3
+ module DatabaseServer
4
+ def delayed_jobs_shard(shard = nil)
5
+ return shard if config[:delayed_jobs_shard] == 'self'
6
+ dj_shard =
7
+ config[:delayed_jobs_shard] &&
8
+ ::Switchman::Shard.lookup(config[:delayed_jobs_shard])
9
+ # have to avoid recursion for the default shard asking for the default
10
+ # shard's delayed_jobs_shard
11
+ dj_shard ||= shard if shard.default?
12
+ dj_shard || ::Switchman::Shard.default.delayed_jobs_shard
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,9 @@
1
+ module SwitchmanInstJobs
2
+ module Switchman
3
+ module DefaultShard
4
+ def delayed_jobs_shard
5
+ self
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,57 @@
1
+ module SwitchmanInstJobs
2
+ module Switchman
3
+ module Shard
4
+ def self.prepended(base)
5
+ base.singleton_class.prepend(ClassMethods)
6
+ end
7
+
8
+ def clear_cache
9
+ self.class.connection.after_transaction_commit { super }
10
+ end
11
+
12
+ def delayed_jobs_shard
13
+ if read_attribute(:delayed_jobs_shard_id)
14
+ shard = ::Switchman::Shard.lookup(delayed_jobs_shard_id)
15
+ return shard if shard
16
+ end
17
+ database_server.try(:delayed_jobs_shard, self)
18
+ end
19
+
20
+ module ClassMethods
21
+ def current(category = :primary)
22
+ if category == :delayed_jobs
23
+ active_shards[category] || super(:primary).delayed_jobs_shard
24
+ else
25
+ super
26
+ end
27
+ end
28
+
29
+ def activate!(categories)
30
+ if !@skip_delayed_job_auto_activation &&
31
+ !categories[:delayed_jobs] &&
32
+ categories[:primary] &&
33
+ categories[:primary] != active_shards[:primary]
34
+ skip_delayed_job_auto_activation do
35
+ categories[:delayed_jobs] =
36
+ categories[:primary].delayed_jobs_shard
37
+ end
38
+ end
39
+ super
40
+ end
41
+
42
+ def skip_delayed_job_auto_activation
43
+ was = @skip_delayed_job_auto_activation
44
+ @skip_delayed_job_auto_activation = true
45
+ yield
46
+ ensure
47
+ @skip_delayed_job_auto_activation = was
48
+ end
49
+
50
+ def create
51
+ db = ::Switchman::DatabaseServer.server_for_new_shard
52
+ db.create_new_shard
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,3 @@
1
+ module SwitchmanInstJobs
2
+ VERSION = '1.0.0'.freeze
3
+ end
metadata ADDED
@@ -0,0 +1,238 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: switchman-inst-jobs
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Bryan Petty
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-04-03 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: inst-jobs
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 0.12.1
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '0.13'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: 0.12.1
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '0.13'
33
+ - !ruby/object:Gem::Dependency
34
+ name: railties
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '4.2'
40
+ - - "<"
41
+ - !ruby/object:Gem::Version
42
+ version: '5.1'
43
+ type: :runtime
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: '4.2'
50
+ - - "<"
51
+ - !ruby/object:Gem::Version
52
+ version: '5.1'
53
+ - !ruby/object:Gem::Dependency
54
+ name: switchman
55
+ requirement: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - "~>"
58
+ - !ruby/object:Gem::Version
59
+ version: 1.9.7
60
+ type: :runtime
61
+ prerelease: false
62
+ version_requirements: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - "~>"
65
+ - !ruby/object:Gem::Version
66
+ version: 1.9.7
67
+ - !ruby/object:Gem::Dependency
68
+ name: bundler
69
+ requirement: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - "~>"
72
+ - !ruby/object:Gem::Version
73
+ version: '1.14'
74
+ type: :development
75
+ prerelease: false
76
+ version_requirements: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - "~>"
79
+ - !ruby/object:Gem::Version
80
+ version: '1.14'
81
+ - !ruby/object:Gem::Dependency
82
+ name: pg
83
+ requirement: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - "~>"
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ type: :development
89
+ prerelease: false
90
+ version_requirements: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - "~>"
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ - !ruby/object:Gem::Dependency
96
+ name: pry
97
+ requirement: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - "~>"
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - "~>"
107
+ - !ruby/object:Gem::Version
108
+ version: '0'
109
+ - !ruby/object:Gem::Dependency
110
+ name: rake
111
+ requirement: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - "~>"
114
+ - !ruby/object:Gem::Version
115
+ version: '12.0'
116
+ type: :development
117
+ prerelease: false
118
+ version_requirements: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - "~>"
121
+ - !ruby/object:Gem::Version
122
+ version: '12.0'
123
+ - !ruby/object:Gem::Dependency
124
+ name: rspec
125
+ requirement: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - "~>"
128
+ - !ruby/object:Gem::Version
129
+ version: '3.5'
130
+ type: :development
131
+ prerelease: false
132
+ version_requirements: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - "~>"
135
+ - !ruby/object:Gem::Version
136
+ version: '3.5'
137
+ - !ruby/object:Gem::Dependency
138
+ name: rspec-rails
139
+ requirement: !ruby/object:Gem::Requirement
140
+ requirements:
141
+ - - "~>"
142
+ - !ruby/object:Gem::Version
143
+ version: '3.5'
144
+ type: :development
145
+ prerelease: false
146
+ version_requirements: !ruby/object:Gem::Requirement
147
+ requirements:
148
+ - - "~>"
149
+ - !ruby/object:Gem::Version
150
+ version: '3.5'
151
+ - !ruby/object:Gem::Dependency
152
+ name: rubocop
153
+ requirement: !ruby/object:Gem::Requirement
154
+ requirements:
155
+ - - "~>"
156
+ - !ruby/object:Gem::Version
157
+ version: '0'
158
+ type: :development
159
+ prerelease: false
160
+ version_requirements: !ruby/object:Gem::Requirement
161
+ requirements:
162
+ - - "~>"
163
+ - !ruby/object:Gem::Version
164
+ version: '0'
165
+ - !ruby/object:Gem::Dependency
166
+ name: simplecov
167
+ requirement: !ruby/object:Gem::Requirement
168
+ requirements:
169
+ - - "~>"
170
+ - !ruby/object:Gem::Version
171
+ version: '0.14'
172
+ type: :development
173
+ prerelease: false
174
+ version_requirements: !ruby/object:Gem::Requirement
175
+ requirements:
176
+ - - "~>"
177
+ - !ruby/object:Gem::Version
178
+ version: '0.14'
179
+ - !ruby/object:Gem::Dependency
180
+ name: wwtd
181
+ requirement: !ruby/object:Gem::Requirement
182
+ requirements:
183
+ - - "~>"
184
+ - !ruby/object:Gem::Version
185
+ version: 1.3.0
186
+ type: :development
187
+ prerelease: false
188
+ version_requirements: !ruby/object:Gem::Requirement
189
+ requirements:
190
+ - - "~>"
191
+ - !ruby/object:Gem::Version
192
+ version: 1.3.0
193
+ description:
194
+ email:
195
+ - bpetty@instructure.com
196
+ executables: []
197
+ extensions: []
198
+ extra_rdoc_files: []
199
+ files:
200
+ - db/migrate/20170308045400_add_shard_id_to_delayed_jobs.rb
201
+ - lib/switchman_inst_jobs.rb
202
+ - lib/switchman_inst_jobs/active_record/connection_adapters/postgresql_adapter.rb
203
+ - lib/switchman_inst_jobs/active_record/migration.rb
204
+ - lib/switchman_inst_jobs/delayed/backend/base.rb
205
+ - lib/switchman_inst_jobs/delayed/message_sending.rb
206
+ - lib/switchman_inst_jobs/delayed/pool.rb
207
+ - lib/switchman_inst_jobs/delayed/worker.rb
208
+ - lib/switchman_inst_jobs/railtie.rb
209
+ - lib/switchman_inst_jobs/shackles.rb
210
+ - lib/switchman_inst_jobs/switchman/database_server.rb
211
+ - lib/switchman_inst_jobs/switchman/default_shard.rb
212
+ - lib/switchman_inst_jobs/switchman/shard.rb
213
+ - lib/switchman_inst_jobs/version.rb
214
+ homepage: https://github.com/instructure/switchman-inst-jobs
215
+ licenses:
216
+ - MIT
217
+ metadata: {}
218
+ post_install_message:
219
+ rdoc_options: []
220
+ require_paths:
221
+ - lib
222
+ required_ruby_version: !ruby/object:Gem::Requirement
223
+ requirements:
224
+ - - ">="
225
+ - !ruby/object:Gem::Version
226
+ version: '2.3'
227
+ required_rubygems_version: !ruby/object:Gem::Requirement
228
+ requirements:
229
+ - - ">="
230
+ - !ruby/object:Gem::Version
231
+ version: '0'
232
+ requirements: []
233
+ rubyforge_project:
234
+ rubygems_version: 2.5.2
235
+ signing_key:
236
+ specification_version: 4
237
+ summary: Switchman and Instructure Jobs compatibility gem.
238
+ test_files: []