switchman-inst-jobs 1.0.0

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: 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: []