good_job 2.6.2 → 2.7.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.
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