good_job 2.6.2 → 2.7.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6815620f600cf3f925daf7a5f13074f79ee26d7ab16b28b28c3be9e1ac2b9ac9
4
- data.tar.gz: b7befdf977e9bebe94ac2707bea503c9e60e112045838885ee398a319026af9c
3
+ metadata.gz: f44a377e368104479ccd928977d0c99c673e468fdcce61530cdfef1ee045c61d
4
+ data.tar.gz: 3a5b29ba222be53ee571036ed27275517cb810a03bbd9b6fa5733b215742ef50
5
5
  SHA512:
6
- metadata.gz: ba25873794f78d9e7081a0ae387d4e2c8cf6de96eaa28859e7fe565d85261de57538680f00d172f6eadcb91c157c1d2f34d66df2a630e94440b55fdd1f8ded05
7
- data.tar.gz: 76a0d3cd4b76758f72a81f99a04aff2ea50396828b7fa4c440a3d401c01fc4accfb9d821f333b3ff71d517be565f9f9376ad27da5742611ff1744bc70c7d2f16
6
+ metadata.gz: 833b35f3faa5660d45e14adbb15d2b6f65c7a7cbc127ae0d6d9085844e55fe33c6c1b02cbb6196f5f753bdf7ec76cff18a1976cef3ca26288960f6028c6d3fac
7
+ data.tar.gz: def64d311e93139e7232fddd9aec1f0c0e0ff49696680dede67f87705d3a0dbc9338d083f1f2a22fdfff572465032c6ec75c97dee1ece7ffac20ca46c76fdc6c
data/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # Changelog
2
2
 
3
+ ## [v2.7.0](https://github.com/bensheldon/good_job/tree/v2.7.0) (2021-11-10)
4
+
5
+ [Full Changelog](https://github.com/bensheldon/good_job/compare/v2.6.2...v2.7.0)
6
+
7
+ **Implemented enhancements:**
8
+
9
+ - Add http probe for CLI healthcheck/readiness/liveliness [\#452](https://github.com/bensheldon/good_job/pull/452) ([bensheldon](https://github.com/bensheldon))
10
+ - Add explicit Content Security Policy \(CSP\) for Dashboard [\#449](https://github.com/bensheldon/good_job/pull/449) ([bensheldon](https://github.com/bensheldon))
11
+
12
+ **Closed issues:**
13
+
14
+ - Add a default Content-Security-Policy for the Dashboard [\#420](https://github.com/bensheldon/good_job/issues/420)
15
+
3
16
  ## [v2.6.2](https://github.com/bensheldon/good_job/tree/v2.6.2) (2021-11-05)
4
17
 
5
18
  [Full Changelog](https://github.com/bensheldon/good_job/compare/v2.6.1...v2.6.2)
data/README.md CHANGED
@@ -55,6 +55,7 @@ For more of the story of GoodJob, read the [introductory blog post](https://isla
55
55
  - [Migrate to GoodJob from a different ActiveJob backend](#migrate-to-goodjob-from-a-different-activejob-backend)
56
56
  - [Monitor and preserve worked jobs](#monitor-and-preserve-worked-jobs)
57
57
  - [PgBouncer compatibility](#pgbouncer-compatibility)
58
+ - [CLI HTTP health check probes](#cli-http-healthcheck-probes)
58
59
  - [Contribute](#contribute)
59
60
  - [Gem development](#gem-development)
60
61
  - [Release](#release)
@@ -170,6 +171,7 @@ Options:
170
171
  [--enable-cron] # Whether to run cron process (default: false)
171
172
  [--daemonize] # Run as a background daemon (default: false)
172
173
  [--pidfile=PIDFILE] # Path to write daemonized Process ID (env var: GOOD_JOB_PIDFILE, default: tmp/pids/good_job.pid)
174
+ [--probe-port=PORT] # Port for http health check (env var: GOOD_JOB_PROBE_PORT, default: nil)
173
175
 
174
176
  Executes queued jobs.
175
177
 
@@ -837,6 +839,61 @@ A workaround to this limitation is to make a direct database connection availabl
837
839
  GoodJob.active_record_parent_class = "ApplicationDirectRecord"
838
840
  ```
839
841
 
842
+ ### CLI HTTP health check probes
843
+
844
+ GoodJob's CLI offers an http health check probe to better manage process lifecycle in containerized environments like Kubernetes:
845
+
846
+ ```bash
847
+ # Run the CLI with a health check on port 7001
848
+ good_job start --probe-port=7001
849
+
850
+ # or via an environment variable
851
+ GOOD_JOB_PROBE_PORT=7001 good_job start
852
+
853
+ # Probe the status
854
+ curl localhost:7001/status
855
+ curl localhost:7001/status/started
856
+ curl localhost:7001/status/connected
857
+ ```
858
+
859
+ Multiple health checks are available at different paths:
860
+
861
+ - `/` or `/status`: the CLI process is running
862
+ - `/status/started`: the multithreaded job executor is running
863
+ - `/status/connected`: the database connection is established
864
+
865
+ This can be configured, for example with Kubernetes:
866
+
867
+ ```yaml
868
+ spec:
869
+ containers:
870
+ - name: good_job
871
+ image: my_app:latest
872
+ env:
873
+ - name: RAILS_ENV
874
+ value: production
875
+ - name: GOOD_JOB_PROBE_PORT
876
+ value: 7001
877
+ command:
878
+ - good_job
879
+ - start
880
+ ports:
881
+ - name: probe-port
882
+ containerPort: 7001
883
+ startupProbe:
884
+ httpGet:
885
+ path: "/status/started"
886
+ port: probe-port
887
+ failureThreshold: 30
888
+ periodSeconds: 10
889
+ livenessProbe:
890
+ httpGet:
891
+ path: "/status/connected"
892
+ port: probe-port
893
+ failureThreshold: 1
894
+ periodSeconds: 10
895
+ ```
896
+
840
897
  ## Contribute
841
898
 
842
899
  Contributions are welcomed and appreciated 🙏
@@ -5,6 +5,25 @@ module GoodJob
5
5
 
6
6
  around_action :switch_locale
7
7
 
8
+ content_security_policy do |policy|
9
+ policy.default_src(:none) if policy.default_src.blank?
10
+ policy.connect_src(:self) if policy.connect_src.blank?
11
+ policy.base_uri(:none) if policy.base_uri.blank?
12
+ policy.font_src(:self) if policy.font_src.blank?
13
+ policy.img_src(:self, :data) if policy.img_src.blank?
14
+ policy.object_src(:none) if policy.object_src.blank?
15
+ policy.script_src(:self) if policy.script_src.blank?
16
+ policy.style_src(:self) if policy.style_src.blank?
17
+ policy.form_action(:self) if policy.form_action.blank?
18
+ policy.frame_ancestors(:none) if policy.frame_ancestors.blank?
19
+ end
20
+
21
+ before_action do
22
+ next if request.content_security_policy_nonce_generator
23
+
24
+ request.content_security_policy_nonce_generator = ->(_request) { SecureRandom.base64(16) }
25
+ end
26
+
8
27
  private
9
28
 
10
29
  def switch_locale(&action)
data/lib/good_job/cli.rb CHANGED
@@ -79,6 +79,9 @@ module GoodJob
79
79
  method_option :pidfile,
80
80
  type: :string,
81
81
  desc: "Path to write daemonized Process ID (env var: GOOD_JOB_PIDFILE, default: tmp/pids/good_job.pid)"
82
+ method_option :probe_port,
83
+ type: :numeric,
84
+ desc: "Port for http health check (env var: GOOD_JOB_PROBE_PORT, default: nil)"
82
85
 
83
86
  def start
84
87
  set_up_application!
@@ -93,6 +96,10 @@ module GoodJob
93
96
  poller.recipients << [scheduler, :create_thread]
94
97
 
95
98
  cron_manager = GoodJob::CronManager.new(configuration.cron_entries, start_on_initialize: true) if configuration.enable_cron?
99
+ if configuration.probe_port
100
+ probe_server = GoodJob::ProbeServer.new(port: configuration.probe_port)
101
+ probe_server.start
102
+ end
96
103
 
97
104
  @stop_good_job_executable = false
98
105
  %w[INT TERM].each do |signal|
@@ -106,6 +113,7 @@ module GoodJob
106
113
 
107
114
  executors = [notifier, poller, cron_manager, scheduler].compact
108
115
  GoodJob._shutdown_all(executors, timeout: configuration.shutdown_timeout)
116
+ probe_server&.stop
109
117
  end
110
118
 
111
119
  default_task :start
@@ -195,6 +195,13 @@ module GoodJob
195
195
  Rails.application.root.join('tmp', 'pids', 'good_job.pid')
196
196
  end
197
197
 
198
+ # Port of the probe server
199
+ # @return [nil,Integer]
200
+ def probe_port
201
+ options[:probe_port] ||
202
+ env['GOOD_JOB_PROBE_PORT']
203
+ end
204
+
198
205
  private
199
206
 
200
207
  def rails_config
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GoodJob
4
+ class ProbeServer
5
+ RACK_SERVER = 'webrick'
6
+
7
+ def self.task_observer(time, output, thread_error) # rubocop:disable Lint/UnusedMethodArgument
8
+ return if thread_error.is_a? Concurrent::CancelledOperationError
9
+
10
+ GoodJob.on_thread_error.call(thread_error) if thread_error && GoodJob.on_thread_error.respond_to?(:call)
11
+ end
12
+
13
+ def initialize(port:)
14
+ @port = port
15
+ end
16
+
17
+ def start
18
+ @handler = Rack::Handler.get(RACK_SERVER)
19
+ @future = Concurrent::Future.new(args: [@handler, @port, GoodJob.logger]) do |thr_handler, thr_port, thr_logger|
20
+ thr_handler.run(self, Port: thr_port, Logger: thr_logger, AccessLog: [])
21
+ end
22
+ @future.add_observer(self.class, :task_observer)
23
+ @future.execute
24
+ end
25
+
26
+ def running?
27
+ @handler&.instance_variable_get(:@server)&.status == :Running
28
+ end
29
+
30
+ def stop
31
+ @handler&.shutdown
32
+ @future&.value # wait for Future to exit
33
+ end
34
+
35
+ def call(env)
36
+ case Rack::Request.new(env).path
37
+ when '/', '/status'
38
+ [200, {}, ["OK"]]
39
+ when '/status/started'
40
+ started = GoodJob::Scheduler.instances.any? && GoodJob::Scheduler.instances.all?(&:running?)
41
+ started ? [200, {}, ["Started"]] : [503, {}, ["Not started"]]
42
+ when '/status/connected'
43
+ connected = GoodJob::Scheduler.instances.any? && GoodJob::Scheduler.instances.all?(&:running?) &&
44
+ GoodJob::Notifier.instances.any? && GoodJob::Notifier.instances.all?(&:listening?)
45
+ connected ? [200, {}, ["Connected"]] : [503, {}, ["Not connected"]]
46
+ else
47
+ [404, {}, ["Not found"]]
48
+ end
49
+ end
50
+ end
51
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
  module GoodJob
3
3
  # GoodJob gem version.
4
- VERSION = '2.6.2'
4
+ VERSION = '2.7.0'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: good_job
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.6.2
4
+ version: 2.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ben Sheldon
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-11-05 00:00:00.000000000 Z
11
+ date: 2021-11-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activejob
@@ -94,6 +94,20 @@ dependencies:
94
94
  - - ">="
95
95
  - !ruby/object:Gem::Version
96
96
  version: 0.14.1
97
+ - !ruby/object:Gem::Dependency
98
+ name: webrick
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '1.3'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '1.3'
97
111
  - !ruby/object:Gem::Dependency
98
112
  name: zeitwerk
99
113
  requirement: !ruby/object:Gem::Requirement
@@ -410,6 +424,7 @@ files:
410
424
  - lib/good_job/multi_scheduler.rb
411
425
  - lib/good_job/notifier.rb
412
426
  - lib/good_job/poller.rb
427
+ - lib/good_job/probe_server.rb
413
428
  - lib/good_job/railtie.rb
414
429
  - lib/good_job/scheduler.rb
415
430
  - lib/good_job/version.rb