resque-kubernetes 0.10.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -1
- data/Appraisals +9 -0
- data/CHANGELOG.md +15 -0
- data/README.md +37 -19
- data/Rakefile +8 -2
- data/gemfiles/kubeclient_3.gemfile +7 -0
- data/gemfiles/kubeclient_4.gemfile +7 -0
- data/lib/resque/kubernetes/context/kubectl.rb +43 -0
- data/lib/resque/kubernetes/context/well_known.rb +40 -0
- data/lib/resque/kubernetes/context_factory.rb +8 -53
- data/lib/resque/kubernetes/jobs_manager.rb +11 -13
- data/lib/resque/kubernetes/version.rb +1 -1
- data/lib/resque/kubernetes.rb +5 -3
- data/resque-kubernetes.gemspec +2 -1
- metadata +26 -8
- data/lib/resque/kubernetes/worker.rb +0 -52
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dd653a29a38d097f457584f8bb8a4b305dc14f1f
|
4
|
+
data.tar.gz: 4ac673bc617fdd91c99fe3b51f0c943f214655f6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 142a38eea17c227b6339eef837b58e4835d3fdf05d7f76f85f30cde00c25f6d20b3ee1fa59795b030549283bfcae28eb49da8159449bd3004066c258c5a7b4d0
|
7
|
+
data.tar.gz: 707c7a76de380e87d8da7c4f4651d924f9b7992d5bdedcf48150a0ce8c225cda21d9f252f4a4b907dae373c5c012be2f9ec449bb69d90501a711607f2161b3e2
|
data/.gitignore
CHANGED
data/Appraisals
ADDED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,18 @@
|
|
1
|
+
# v1.1.0
|
2
|
+
- Fix design to set `INTERVAL=0` for the worker in the Kubernetes
|
3
|
+
job manifest, which tells `resque` to work until there are no more jobs,
|
4
|
+
rather than monkey-patching `Resque::Worker` to look for `TERM_ON_EMPTY`
|
5
|
+
environment variable.
|
6
|
+
|
7
|
+
# v1.0.0
|
8
|
+
**Breaking Change:**
|
9
|
+
- Requires `kubeclient` 3.1.2 or 4.x
|
10
|
+
|
11
|
+
**Changes:**
|
12
|
+
- Add `kubeclient` configuration option for connecting to any Kubernetes server
|
13
|
+
- Use kubernetes namespace provided by cluster or `kubectl` configuration when available
|
14
|
+
- Add Appraisal for testing with kubeclient 3.1.2 and 4.x
|
15
|
+
|
1
16
|
# v0.10.0
|
2
17
|
- `kubeclient` may not be later than 3.0.0 due to change in signature of `Kubeclient::Config::Context#initialize`
|
3
18
|
in `kubeclient` 3.1.0
|
data/README.md
CHANGED
@@ -7,8 +7,8 @@ the container finishes and then it terminates the pod (as opposed to trying to
|
|
7
7
|
restart the container).
|
8
8
|
|
9
9
|
This gem takes advantage of that feature by starting up a Kubernetes Job to
|
10
|
-
run a worker when a Resque job or ActiveJob is enqueued. It then
|
11
|
-
Resque worker to
|
10
|
+
run a worker when a Resque job or ActiveJob is enqueued. It then tells the
|
11
|
+
Resque worker to run until there are no more jobs in the queue.
|
12
12
|
|
13
13
|
Why would you do this?
|
14
14
|
|
@@ -122,15 +122,18 @@ class ResourceIntensiveJob < ApplicationJob
|
|
122
122
|
end
|
123
123
|
end
|
124
124
|
```
|
125
|
-
|
126
125
|
### Workers (for both)
|
127
126
|
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
127
|
+
The resque worker can can be any container image that runs the `resque:work` `rake` task, for example:
|
128
|
+
|
129
|
+
```bash
|
130
|
+
bin/rails environment resque:work
|
131
|
+
```
|
132
|
+
|
133
|
+
The gem sets the environment variable `INTERVAL=0` for the Kubernetes Job which the `rake` task uses
|
134
|
+
to when calling `Resque::Worker#work(interval)`. The value 0 tells Resque to terminate when the queue
|
135
|
+
is empty. If your Docker image does not run the rake task, then you'll need to make sure you pass 0
|
136
|
+
for the interval when calling `Resque::Worker#work`.
|
134
137
|
|
135
138
|
### Job manifest
|
136
139
|
|
@@ -200,13 +203,28 @@ class ResourceIntensiveJob
|
|
200
203
|
end
|
201
204
|
```
|
202
205
|
|
203
|
-
|
206
|
+
### kubeclient
|
207
|
+
|
208
|
+
The gem will automatically connect to the Kubernetes server in the following cases:
|
209
|
+
- You are running this in [a standard Kubernetes cluster](https://kubernetes.io/docs/tasks/access-application-cluster/access-cluster/#accessing-the-api-from-a-pod)
|
210
|
+
- You are running on a system with `kubeclient` installed and
|
211
|
+
- the default cluster context has credentials
|
212
|
+
- the default cluster is GKE and your system has
|
213
|
+
[Google application default credentials](https://developers.google.com/identity/protocols/application-default-credentials)
|
214
|
+
installed
|
215
|
+
|
216
|
+
There are many other ways to connect and you can do so by providing your own
|
217
|
+
[configured `kubeclient`](https://github.com/abonas/kubeclient#usage):
|
218
|
+
|
219
|
+
```ruby
|
220
|
+
# config/initializers/resque-kubernetes.rb
|
221
|
+
|
222
|
+
Resque::Kubernetes.configuration do |config|
|
223
|
+
config.kubeclient = Kubeclient::Client.new("http://localhost:8080/apis/batch")
|
224
|
+
end
|
225
|
+
```
|
204
226
|
|
205
|
-
|
206
|
-
See [the many examples](https://github.com/abonas/kubeclient#usage) in their
|
207
|
-
README.
|
208
|
-
- We probably need better namespace support, particularly for reaping
|
209
|
-
finished jobs and pods.
|
227
|
+
Because this uses the `Job` resource, make sure to connect to the `/apis/batch` API endpoint in your client.
|
210
228
|
|
211
229
|
## Contributing
|
212
230
|
|
@@ -231,7 +249,7 @@ experiment.
|
|
231
249
|
|
232
250
|
Write test for any code that you add. Test all changes by running `rake`.
|
233
251
|
This does the following, which you can also run separately while working.
|
234
|
-
1.
|
252
|
+
1. Run unit tests: `appraisal rake spec`
|
235
253
|
2. Make sure that your code matches the styles: `rubocop`
|
236
254
|
3. Verify if any dependent gems have open CVEs (you must update these):
|
237
255
|
`rake bundle:audit`
|
@@ -239,10 +257,10 @@ This does the following, which you can also run separately while working.
|
|
239
257
|
### End to End Tests
|
240
258
|
|
241
259
|
We don't run End to End (e2e) tests in the regular suite because
|
242
|
-
they require a connection to a cluster. You
|
243
|
-
|
260
|
+
they require a connection to a cluster. You should run these on your changes
|
261
|
+
to verify that the jobs are created correctly.
|
244
262
|
|
245
|
-
This will use the default authentication on your system, which
|
263
|
+
This will use the default authentication on your system, which is either
|
246
264
|
the cluster the tests are running in (if you are doing that), your `kubclient`
|
247
265
|
configuration, or your Google Default Application Credentials.
|
248
266
|
|
data/Rakefile
CHANGED
@@ -1,16 +1,22 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "appraisal/task"
|
4
|
+
require "bundler/audit/task"
|
3
5
|
require "bundler/gem_tasks"
|
4
6
|
require "rspec/core/rake_task"
|
5
7
|
require "rubocop/rake_task"
|
6
|
-
require "bundler/audit/task"
|
7
8
|
|
8
9
|
RSpec::Core::RakeTask.new(:spec)
|
9
10
|
RuboCop::RakeTask.new
|
10
11
|
Bundler::Audit::Task.new
|
12
|
+
Appraisal::Task.new
|
11
13
|
|
12
14
|
# Remove default and replace with a series of test tasks
|
13
15
|
task default: []
|
14
16
|
Rake::Task[:default].clear
|
15
17
|
|
16
|
-
|
18
|
+
if ENV["APPRAISAL_INITIALIZED"]
|
19
|
+
task default: %i[spec]
|
20
|
+
else
|
21
|
+
task default: %i[rubocop bundle:audit appraisal]
|
22
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Resque
|
4
|
+
module Kubernetes
|
5
|
+
module Context
|
6
|
+
# Kubeclient Context from `kubectl` config file.
|
7
|
+
class Kubectl
|
8
|
+
def applicable?
|
9
|
+
File.exist?(kubeconfig)
|
10
|
+
end
|
11
|
+
|
12
|
+
def context
|
13
|
+
config = Kubeclient::Config.read(kubeconfig)
|
14
|
+
|
15
|
+
Resque::Kubernetes::ContextFactory::Context.new(
|
16
|
+
config.context.api_endpoint,
|
17
|
+
config.context.api_version,
|
18
|
+
config.context.namespace,
|
19
|
+
auth_options: auth_options(config),
|
20
|
+
ssl_options: config.context.ssl_options
|
21
|
+
)
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def kubeconfig
|
27
|
+
File.join(ENV["HOME"], ".kube", "config")
|
28
|
+
end
|
29
|
+
|
30
|
+
def auth_options(config)
|
31
|
+
options = config.context.auth_options
|
32
|
+
return options unless options.empty?
|
33
|
+
google_application_default_credentials
|
34
|
+
end
|
35
|
+
|
36
|
+
def google_application_default_credentials
|
37
|
+
return unless defined?(Google) && defined?(Google::Auth)
|
38
|
+
{bearer_token: Kubeclient::GoogleApplicationDefaultCredentials.token}
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Resque
|
4
|
+
module Kubernetes
|
5
|
+
module Context
|
6
|
+
# Kubeclient Context from well-known locations within a Kubernetes cluster.
|
7
|
+
class WellKnown
|
8
|
+
TOKEN_FILE = "/var/run/secrets/kubernetes.io/serviceaccount/token"
|
9
|
+
CA_FILE = "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"
|
10
|
+
NAMESPACE_FILE = "/var/run/secrets/kubernetes.io/serviceaccount/namespace"
|
11
|
+
|
12
|
+
def applicable?
|
13
|
+
File.exist?(TOKEN_FILE)
|
14
|
+
end
|
15
|
+
|
16
|
+
def context
|
17
|
+
Resque::Kubernetes::ContextFactory::Context.new(
|
18
|
+
"https://kubernetes.default.svc",
|
19
|
+
"v1",
|
20
|
+
namespace,
|
21
|
+
auth_options: {bearer_token_file: TOKEN_FILE},
|
22
|
+
ssl_options: ssl_options
|
23
|
+
)
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def namespace
|
29
|
+
return nil unless File.exist?(NAMESPACE_FILE)
|
30
|
+
File.read(NAMESPACE_FILE)
|
31
|
+
end
|
32
|
+
|
33
|
+
def ssl_options
|
34
|
+
return {} unless File.exist?(CA_FILE)
|
35
|
+
{ca_file: CA_FILE}
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -6,64 +6,19 @@ module Resque
|
|
6
6
|
module Kubernetes
|
7
7
|
# Create a context for `Kubeclient` depending on the environment.
|
8
8
|
class ContextFactory
|
9
|
+
Context = Struct.new(:endpoint, :version, :namespace, :options)
|
10
|
+
|
9
11
|
class << self
|
10
12
|
def context
|
11
13
|
# TODO: Add ability to load this from config
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
kubectl_context
|
14
|
+
[
|
15
|
+
Resque::Kubernetes::Context::WellKnown,
|
16
|
+
Resque::Kubernetes::Context::Kubectl
|
17
|
+
].each do |context_type|
|
18
|
+
context = context_type.new
|
19
|
+
return context.context if context.applicable?
|
19
20
|
end
|
20
21
|
end
|
21
|
-
|
22
|
-
private
|
23
|
-
|
24
|
-
def well_known_context
|
25
|
-
Kubeclient::Config::Context.new(
|
26
|
-
"https://kubernetes",
|
27
|
-
"v1",
|
28
|
-
{ca_file: "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"},
|
29
|
-
bearer_token_file: "/var/run/secrets/kubernetes.io/serviceaccount/token"
|
30
|
-
)
|
31
|
-
end
|
32
|
-
|
33
|
-
def kubectl_context
|
34
|
-
config = Kubeclient::Config.read(kubeconfig)
|
35
|
-
auth_options = config.context.auth_options
|
36
|
-
|
37
|
-
auth_options = google_default_application_credentials(config) if auth_options.empty?
|
38
|
-
|
39
|
-
Kubeclient::Config::Context.new(
|
40
|
-
config.context.api_endpoint,
|
41
|
-
config.context.api_version,
|
42
|
-
config.context.ssl_options,
|
43
|
-
auth_options
|
44
|
-
)
|
45
|
-
end
|
46
|
-
|
47
|
-
def kubeconfig
|
48
|
-
File.join(ENV["HOME"], ".kube", "config")
|
49
|
-
end
|
50
|
-
|
51
|
-
# TODO: Move this logic to kubeclient. See abonas/kubeclient#213
|
52
|
-
def google_default_application_credentials(config)
|
53
|
-
return unless defined?(Google) && defined?(Google::Auth)
|
54
|
-
|
55
|
-
_cluster, user = config.send(:fetch_context, config.instance_variable_get(:@kcfg)["current-context"])
|
56
|
-
return {} unless user["auth-provider"] && user["auth-provider"]["name"] == "gcp"
|
57
|
-
|
58
|
-
{bearer_token: new_google_token}
|
59
|
-
end
|
60
|
-
|
61
|
-
def new_google_token
|
62
|
-
scopes = ["https://www.googleapis.com/auth/cloud-platform"]
|
63
|
-
authorization = Google::Auth.get_application_default(scopes)
|
64
|
-
authorization.apply({})
|
65
|
-
authorization.access_token
|
66
|
-
end
|
67
22
|
end
|
68
23
|
end
|
69
24
|
end
|
@@ -10,7 +10,8 @@ module Resque
|
|
10
10
|
private :owner
|
11
11
|
|
12
12
|
def initialize(owner)
|
13
|
-
@owner
|
13
|
+
@owner = owner
|
14
|
+
@default_namespace = "default"
|
14
15
|
end
|
15
16
|
|
16
17
|
def reap_finished_jobs
|
@@ -39,20 +40,17 @@ module Resque
|
|
39
40
|
private
|
40
41
|
|
41
42
|
def jobs_client
|
42
|
-
|
43
|
-
@jobs_client = client("/apis/batch")
|
43
|
+
@jobs_client ||= client("/apis/batch")
|
44
44
|
end
|
45
45
|
|
46
46
|
def client(scope)
|
47
|
+
return Resque::Kubernetes.kubeclient if Resque::Kubernetes.kubeclient
|
48
|
+
|
47
49
|
context = ContextFactory.context
|
48
50
|
return unless context
|
51
|
+
@default_namespace = context.namespace if context.namespace
|
49
52
|
|
50
|
-
Kubeclient::Client.new(
|
51
|
-
context.api_endpoint + scope,
|
52
|
-
context.api_version,
|
53
|
-
ssl_options: context.ssl_options,
|
54
|
-
auth_options: context.auth_options
|
55
|
-
)
|
53
|
+
Kubeclient::Client.new(context.endpoint + scope, context.version, context.options)
|
56
54
|
end
|
57
55
|
|
58
56
|
def finished_jobs
|
@@ -92,12 +90,12 @@ module Resque
|
|
92
90
|
|
93
91
|
def container_term_on_empty(container)
|
94
92
|
container["env"] ||= []
|
95
|
-
term_on_empty = container["env"].find { |env| env["name"] == "
|
93
|
+
term_on_empty = container["env"].find { |env| env["name"] == "INTERVAL" }
|
96
94
|
unless term_on_empty
|
97
|
-
term_on_empty = {"name" => "
|
95
|
+
term_on_empty = {"name" => "INTERVAL"}
|
98
96
|
container["env"] << term_on_empty
|
99
97
|
end
|
100
|
-
term_on_empty["value"] = "
|
98
|
+
term_on_empty["value"] = "0"
|
101
99
|
end
|
102
100
|
|
103
101
|
def ensure_reset_policy(manifest)
|
@@ -105,7 +103,7 @@ module Resque
|
|
105
103
|
end
|
106
104
|
|
107
105
|
def ensure_namespace(manifest)
|
108
|
-
manifest["metadata"]["namespace"] ||=
|
106
|
+
manifest["metadata"]["namespace"] ||= @default_namespace
|
109
107
|
end
|
110
108
|
|
111
109
|
def update_job_name(manifest)
|
data/lib/resque/kubernetes.rb
CHANGED
@@ -1,13 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "resque/kubernetes/configurable"
|
4
|
+
require "resque/kubernetes/context/kubectl"
|
5
|
+
require "resque/kubernetes/context/well_known"
|
4
6
|
require "resque/kubernetes/context_factory"
|
5
7
|
require "resque/kubernetes/deep_hash"
|
6
8
|
require "resque/kubernetes/dns_safe_random"
|
7
9
|
require "resque/kubernetes/job"
|
8
10
|
require "resque/kubernetes/jobs_manager"
|
9
11
|
require "resque/kubernetes/version"
|
10
|
-
require "resque/kubernetes/worker"
|
11
12
|
|
12
13
|
module Resque
|
13
14
|
# Run Resque Jobs as Kubernetes Jobs with autoscaling.
|
@@ -19,7 +20,8 @@ module Resque
|
|
19
20
|
|
20
21
|
# Limit the number of workers that should be spun up, default 10
|
21
22
|
define_setting :max_workers, 10
|
23
|
+
|
24
|
+
# A `kubeclient` for connection context, default attempts to read from cluster or `~/.kube/config`
|
25
|
+
define_setting :kubeclient, nil
|
22
26
|
end
|
23
27
|
end
|
24
|
-
|
25
|
-
Resque::Worker.include Resque::Kubernetes::Worker
|
data/resque-kubernetes.gemspec
CHANGED
@@ -23,6 +23,7 @@ Gem::Specification.new do |spec|
|
|
23
23
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
24
24
|
spec.require_paths = ["lib"]
|
25
25
|
|
26
|
+
spec.add_development_dependency "appraisal"
|
26
27
|
spec.add_development_dependency "bundler", "~> 1.16"
|
27
28
|
spec.add_development_dependency "bundler-audit", "~> 0"
|
28
29
|
spec.add_development_dependency "googleauth", "~> 0.6"
|
@@ -30,6 +31,6 @@ Gem::Specification.new do |spec|
|
|
30
31
|
spec.add_development_dependency "rspec", "~> 3.7"
|
31
32
|
spec.add_development_dependency "rubocop", "~> 0.52", ">= 0.52.1"
|
32
33
|
|
33
|
-
spec.add_dependency "kubeclient", ">=
|
34
|
+
spec.add_dependency "kubeclient", ">= 3.1.2", "< 5.0"
|
34
35
|
spec.add_dependency "resque", "~> 1.26"
|
35
36
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: resque-kubernetes
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeremy Wadsack
|
@@ -10,6 +10,20 @@ bindir: exe
|
|
10
10
|
cert_chain: []
|
11
11
|
date: 2018-09-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: appraisal
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: bundler
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -106,20 +120,20 @@ dependencies:
|
|
106
120
|
requirements:
|
107
121
|
- - ">="
|
108
122
|
- !ruby/object:Gem::Version
|
109
|
-
version:
|
110
|
-
- - "
|
123
|
+
version: 3.1.2
|
124
|
+
- - "<"
|
111
125
|
- !ruby/object:Gem::Version
|
112
|
-
version:
|
126
|
+
version: '5.0'
|
113
127
|
type: :runtime
|
114
128
|
prerelease: false
|
115
129
|
version_requirements: !ruby/object:Gem::Requirement
|
116
130
|
requirements:
|
117
131
|
- - ">="
|
118
132
|
- !ruby/object:Gem::Version
|
119
|
-
version:
|
120
|
-
- - "
|
133
|
+
version: 3.1.2
|
134
|
+
- - "<"
|
121
135
|
- !ruby/object:Gem::Version
|
122
|
-
version:
|
136
|
+
version: '5.0'
|
123
137
|
- !ruby/object:Gem::Dependency
|
124
138
|
name: resque
|
125
139
|
requirement: !ruby/object:Gem::Requirement
|
@@ -147,6 +161,7 @@ files:
|
|
147
161
|
- ".rubocop.yml"
|
148
162
|
- ".ruby-gemset"
|
149
163
|
- ".ruby-version"
|
164
|
+
- Appraisals
|
150
165
|
- CHANGELOG.md
|
151
166
|
- Gemfile
|
152
167
|
- LICENSE.txt
|
@@ -154,15 +169,18 @@ files:
|
|
154
169
|
- Rakefile
|
155
170
|
- bin/console
|
156
171
|
- bin/setup
|
172
|
+
- gemfiles/kubeclient_3.gemfile
|
173
|
+
- gemfiles/kubeclient_4.gemfile
|
157
174
|
- lib/resque/kubernetes.rb
|
158
175
|
- lib/resque/kubernetes/configurable.rb
|
176
|
+
- lib/resque/kubernetes/context/kubectl.rb
|
177
|
+
- lib/resque/kubernetes/context/well_known.rb
|
159
178
|
- lib/resque/kubernetes/context_factory.rb
|
160
179
|
- lib/resque/kubernetes/deep_hash.rb
|
161
180
|
- lib/resque/kubernetes/dns_safe_random.rb
|
162
181
|
- lib/resque/kubernetes/job.rb
|
163
182
|
- lib/resque/kubernetes/jobs_manager.rb
|
164
183
|
- lib/resque/kubernetes/version.rb
|
165
|
-
- lib/resque/kubernetes/worker.rb
|
166
184
|
- resque-kubernetes.gemspec
|
167
185
|
homepage: https://github.com/keylimetoolbox/resque-kubernetes
|
168
186
|
licenses:
|
@@ -1,52 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "resque"
|
4
|
-
|
5
|
-
module Resque
|
6
|
-
module Kubernetes
|
7
|
-
# Patches the resque worker to terminate when the queue is empty.
|
8
|
-
#
|
9
|
-
# This patch enables setting an environment variable, `TERM_ON_EMPTY`
|
10
|
-
# that causes the worker to shutdown when the queue no longer has any
|
11
|
-
# resque jobs. This allows running workers as Kuberenetes Jobs that will
|
12
|
-
# terminate when there is no longer any work to do.
|
13
|
-
#
|
14
|
-
# To use, make sure that the container images that hold your workers are
|
15
|
-
# built to include the `resque-kubernetes` gem and set `TERM_ON_EMPTY` in
|
16
|
-
# their environment to a truthy value (e.g. "1").
|
17
|
-
module Worker
|
18
|
-
def self.included(base)
|
19
|
-
base.class_eval do
|
20
|
-
prepend InstanceMethods
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
attr_accessor :term_on_empty
|
25
|
-
|
26
|
-
# Replace methods on the worker instance
|
27
|
-
module InstanceMethods
|
28
|
-
def prepare
|
29
|
-
self.term_on_empty = ENV["TERM_ON_EMPTY"] if ENV["TERM_ON_EMPTY"]
|
30
|
-
super
|
31
|
-
end
|
32
|
-
|
33
|
-
def shutdown?
|
34
|
-
if term_on_empty
|
35
|
-
if queues_empty?
|
36
|
-
log_with_severity :info, "shutdown: queues are empty"
|
37
|
-
shutdown
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
super
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
private
|
46
|
-
|
47
|
-
def queues_empty?
|
48
|
-
queues.all? { |queue| Resque.size(queue).zero? }
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|