blue_green_workers 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/.rspec +3 -0
- data/.rubocop.yml +11 -0
- data/.travis.yml +5 -0
- data/Gemfile +8 -0
- data/README.md +62 -0
- data/Rakefile +9 -0
- data/bin/console +12 -0
- data/bin/setup +8 -0
- data/blue_green_workers.gemspec +37 -0
- data/lib/blue_green_workers/config.rb +34 -0
- data/lib/blue_green_workers/version.rb +5 -0
- data/lib/blue_green_workers.rb +97 -0
- metadata +157 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 763c209e7bb28f7c8e3753cc57d4f3e9d0b1c021
|
4
|
+
data.tar.gz: 1afcd620a1b05e054f56300f0dbdecd0d7509c50
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: fc6b12114e9d32012f262e85fc34f87bb073edfad3ac36d7c846348b7c483db0a22300bdfc407b64c88a3ae74293caf106cac54860605f9800be86bb201cf620
|
7
|
+
data.tar.gz: fd9be9b4151d112db6af2eaffb8d4cacf25e1382f86c8c205dc77f0f2c7a1d77639a10ecca8762db659720ea6f72d80198e49b24c3fdfbad04d4ec622747765f
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.rubocop.yml
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
# BlueGreenWorkers
|
2
|
+
|
3
|
+
This gem provides helpers to coordiante workers across multiple clusters that for which only one cluster should be active at a time. Think [blue green deployments](https://martinfowler.com/bliki/BlueGreenDeployment.html)
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
gem 'blue_green_workers'
|
9
|
+
```
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install blue_green_workers
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
This gem doesn't attempt to provide an interface through which you specify which cluster is currently active, that's left as an exercise to the reader. One could very easily use ActiveRecord and a simple RESTFul interface to set the current active cluster.
|
22
|
+
|
23
|
+
### Config
|
24
|
+
```ruby
|
25
|
+
BlueGreenWorkers.configure do |config|
|
26
|
+
config.cluster_name = 'blue'
|
27
|
+
config.determine_active_cluster { ActiveCluster.first.value }
|
28
|
+
config.activate { QueueClient.listen! }
|
29
|
+
config.deactivate { QueueClient.shutdown! }
|
30
|
+
config.logger = Logger.new STDOUT
|
31
|
+
end
|
32
|
+
```
|
33
|
+
|
34
|
+
* `cluster_name` - Defines the name for this cluster. Something like `ENV['CLUSTER_NAME']` probably makes sense
|
35
|
+
* `determine_active_cluster` - Takes a block that returns the name of the current active cluster
|
36
|
+
* `refresh_interval` (optional) - How often to cache the active cluster, `0` (the default) will call the block passed to `determine_active_cluster` every time a worker is executed.
|
37
|
+
* `activate` (optiona) - Block to call when this cluster goes active. Will be called during initialization. `refresh_interval` must be specified.
|
38
|
+
* `deactivate` (optiona) - Block to call when this cluster goes passive. This block will not be called if the cluster is started in passive mode. `refresh_interval` must be specified.
|
39
|
+
* `logger` (optiona) - Logger to use
|
40
|
+
|
41
|
+
### Executing jobs
|
42
|
+
|
43
|
+
In addition to attaching event handles to `activate` and `deactivate` you can also do this:
|
44
|
+
|
45
|
+
```ruby
|
46
|
+
loop do
|
47
|
+
BlueGreenWorkers.execute do
|
48
|
+
# Do some work, poll for stuff, etc
|
49
|
+
end
|
50
|
+
sleep 60
|
51
|
+
end
|
52
|
+
```
|
53
|
+
|
54
|
+
## Development
|
55
|
+
|
56
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
57
|
+
|
58
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
59
|
+
|
60
|
+
## Contributing
|
61
|
+
|
62
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/hawknewton/blue_green_workers.
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'bundler/setup'
|
5
|
+
require 'blue_green_workers'
|
6
|
+
|
7
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
8
|
+
# with your gem easier. You can also use a different console, if you like.
|
9
|
+
|
10
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
11
|
+
require 'pry'
|
12
|
+
Pry.start
|
data/bin/setup
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
lib = File.expand_path('../lib', __FILE__)
|
5
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
6
|
+
require 'blue_green_workers/version'
|
7
|
+
|
8
|
+
Gem::Specification.new do |spec|
|
9
|
+
spec.name = 'blue_green_workers'
|
10
|
+
spec.version = BlueGreenWorkers::VERSION
|
11
|
+
spec.authors = ['hawknewton']
|
12
|
+
spec.email = ['hawk.newton@gmail.com']
|
13
|
+
|
14
|
+
spec.summary = "Deactivate background workers when we're the standby" \
|
15
|
+
'cluster'
|
16
|
+
spec.description = '
|
17
|
+
Deactive any type of background worker when the cluster is standby. This is
|
18
|
+
useful when deploying apps that utilize timers or queues with a blue/green
|
19
|
+
deploy strategy.
|
20
|
+
'.strip
|
21
|
+
spec.homepage = 'https://github.com/hawknewton/blue_green_workers'
|
22
|
+
|
23
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
24
|
+
f.match(%r{^(test|spec|features)/})
|
25
|
+
end
|
26
|
+
spec.bindir = 'exe'
|
27
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
28
|
+
spec.require_paths = ['lib']
|
29
|
+
|
30
|
+
spec.add_development_dependency 'bundler', '~> 1.16'
|
31
|
+
spec.add_development_dependency 'null-logger', '~> 0.1'
|
32
|
+
spec.add_development_dependency 'pry', '~> 0.11'
|
33
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
34
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
35
|
+
spec.add_development_dependency 'rspec-eventually', '~> 0.2'
|
36
|
+
spec.add_development_dependency 'rubocop', '~> 0.52'
|
37
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'pry'
|
4
|
+
|
5
|
+
module BlueGreenWorkers
|
6
|
+
# Config for BlueGreenWorkers
|
7
|
+
class Config
|
8
|
+
attr_reader :active_cluster_block
|
9
|
+
attr_accessor :cluster_name, :refresh_interval, :activate_block,
|
10
|
+
:deactivate_block
|
11
|
+
attr_writer :logger
|
12
|
+
|
13
|
+
def activate(&block)
|
14
|
+
@activate_block = block
|
15
|
+
end
|
16
|
+
|
17
|
+
def deactivate(&block)
|
18
|
+
@deactivate_block = block
|
19
|
+
end
|
20
|
+
|
21
|
+
def determine_active_cluster(&block)
|
22
|
+
@active_cluster_block = block
|
23
|
+
end
|
24
|
+
|
25
|
+
def logger
|
26
|
+
@logger ||= Logger.new STDOUT
|
27
|
+
end
|
28
|
+
|
29
|
+
def validate
|
30
|
+
cluster_name || raise('No cluster_name defined')
|
31
|
+
active_cluster_block || raise('No determine_active_cluster block defined')
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'blue_green_workers/version'
|
4
|
+
require 'blue_green_workers/config'
|
5
|
+
require 'logger'
|
6
|
+
|
7
|
+
# Main module for blue_green_workers
|
8
|
+
module BlueGreenWorkers
|
9
|
+
def self.active_cluster
|
10
|
+
if config.refresh_interval.positive?
|
11
|
+
@active_cluster
|
12
|
+
else
|
13
|
+
determine_active_cluster
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.configure
|
18
|
+
yield config
|
19
|
+
determine_active_cluster
|
20
|
+
(config.refresh_interval || 0).positive? && start_refresh_thread
|
21
|
+
config.validate
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.execute
|
25
|
+
if config.active_cluster_block.call == config.cluster_name
|
26
|
+
yield
|
27
|
+
else
|
28
|
+
logger.debug 'Workers not active, skipping BlueGreenWorkers#execute'
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.shutdown
|
33
|
+
logger.warn 'Shutting down BlueGreenWotkers!'
|
34
|
+
@refresh_thread&.kill
|
35
|
+
@active_cluster = nil
|
36
|
+
@refresh_thread = nil
|
37
|
+
@config = nil
|
38
|
+
end
|
39
|
+
|
40
|
+
# private
|
41
|
+
def self.activate
|
42
|
+
logger.info 'BlueGreenWorkers cluster activating!'
|
43
|
+
config.activate_block&.call
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.deactivate
|
47
|
+
logger.info 'BlueGreenWorkers cluster deactivating!'
|
48
|
+
config.deactivate_block&.call
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.active_cluster=(cluster)
|
52
|
+
if cluster != @active_cluster
|
53
|
+
if cluster == config.cluster_name
|
54
|
+
activate
|
55
|
+
elsif @active_cluster == config.cluster_name
|
56
|
+
deactivate
|
57
|
+
end
|
58
|
+
end
|
59
|
+
@active_cluster = cluster
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.config
|
63
|
+
@config ||= Config.new
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.determine_active_cluster
|
67
|
+
self.active_cluster = config.active_cluster_block.call
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.logger
|
71
|
+
config.logger
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.refresh_thread
|
75
|
+
logger.info "BlueGreenWorkers refreshing every #{config.refresh_interval}s"
|
76
|
+
@refresh_thread ||= Thread.new { refresh_loop }
|
77
|
+
end
|
78
|
+
|
79
|
+
def self.refresh_loop
|
80
|
+
loop do
|
81
|
+
begin
|
82
|
+
determine_active_cluster
|
83
|
+
sleep config.refresh_interval
|
84
|
+
rescue StandardError => err
|
85
|
+
Logger.error "Error during refresh: #{err} #{err.backtrace.join "\n"}"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def self.start_refresh_thread
|
91
|
+
refresh_thread
|
92
|
+
end
|
93
|
+
|
94
|
+
private_class_method :active_cluster=, :config, :determine_active_cluster,
|
95
|
+
:logger, :refresh_thread, :start_refresh_thread,
|
96
|
+
:refresh_loop
|
97
|
+
end
|
metadata
ADDED
@@ -0,0 +1,157 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: blue_green_workers
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- hawknewton
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-12-20 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.16'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.16'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: null-logger
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.1'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0.1'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: pry
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0.11'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0.11'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '10.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '10.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '3.0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '3.0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rspec-eventually
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0.2'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0.2'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rubocop
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0.52'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0.52'
|
111
|
+
description: |-
|
112
|
+
Deactive any type of background worker when the cluster is standby. This is
|
113
|
+
useful when deploying apps that utilize timers or queues with a blue/green
|
114
|
+
deploy strategy.
|
115
|
+
email:
|
116
|
+
- hawk.newton@gmail.com
|
117
|
+
executables: []
|
118
|
+
extensions: []
|
119
|
+
extra_rdoc_files: []
|
120
|
+
files:
|
121
|
+
- ".gitignore"
|
122
|
+
- ".rspec"
|
123
|
+
- ".rubocop.yml"
|
124
|
+
- ".travis.yml"
|
125
|
+
- Gemfile
|
126
|
+
- README.md
|
127
|
+
- Rakefile
|
128
|
+
- bin/console
|
129
|
+
- bin/setup
|
130
|
+
- blue_green_workers.gemspec
|
131
|
+
- lib/blue_green_workers.rb
|
132
|
+
- lib/blue_green_workers/config.rb
|
133
|
+
- lib/blue_green_workers/version.rb
|
134
|
+
homepage: https://github.com/hawknewton/blue_green_workers
|
135
|
+
licenses: []
|
136
|
+
metadata: {}
|
137
|
+
post_install_message:
|
138
|
+
rdoc_options: []
|
139
|
+
require_paths:
|
140
|
+
- lib
|
141
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
147
|
+
requirements:
|
148
|
+
- - ">="
|
149
|
+
- !ruby/object:Gem::Version
|
150
|
+
version: '0'
|
151
|
+
requirements: []
|
152
|
+
rubyforge_project:
|
153
|
+
rubygems_version: 2.6.13
|
154
|
+
signing_key:
|
155
|
+
specification_version: 4
|
156
|
+
summary: Deactivate background workers when we're the standbycluster
|
157
|
+
test_files: []
|