pg_rails 7.6.46 → 7.6.48

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: 983b0ac59ee7841a5c1a686e35ef35d2e838b012baceecfd1c42cba5e46ff6bf
4
- data.tar.gz: a39c0e76e39a29df881f56528e92b02e0f3ea6273eb37ea7e21d7825158dcfe2
3
+ metadata.gz: 52de9382cb88dfe7488c7594415f2a4d8798985a756b07034c6cfc96c6790352
4
+ data.tar.gz: 62f1058dec67e250f77e2a9e374429664a93507f586b4e6e3a10d659b9141420
5
5
  SHA512:
6
- metadata.gz: b63d7df8af9c3cdb15c041679855fd2040a3db1b5669a7d57017e63111580aedb6c75fffad3c46f008b3a4fb6575ad6753273c599eecb793bdc1a89ad6cbc77b
7
- data.tar.gz: 62d566279fbe3a8aa05dffed007a35b078aeb3215900f8a3e6f8efb015df302c6ea43c321e9ccfbf1ec0218e77e7e8493f072d17b58e35cbcb29a4677fef271e
6
+ metadata.gz: 7b8c70961c4fca0d62d0bd74691914ab262f1e7d1db7f059fc6ba063a250832eb494bb2329e3a84b729b819f7f259efea4555937e52efc2f1e90e5b2f1116402
7
+ data.tar.gz: 6849cb47f9c029f8be0c741efda19024c5078cfadee4caa4b3662460329b83672010e1cf67ed48cf1c0f4b0e4a611f950090d008a5e4f48c2a1c71b655fe3d29
@@ -6,83 +6,26 @@ module PgEngine
6
6
  render_down
7
7
  end
8
8
 
9
+ # Examples:
10
+ # ?except=["good_job", "ssl", "websocket"]
11
+ # ?only=["redis"]
9
12
  def show
10
- check_redis
11
- check_postgres
12
- check_websocket
13
- check_ssl
14
- # FIXME: make configurable
15
- check_good_job unless ENV.fetch("HEALTH_CHECK_SKIP_GOOD_JOB", nil) == "1"
13
+ HealthChecker.new.run_checks(
14
+ only: parse_ary(params[:only]),
15
+ except: parse_ary(params[:except])
16
+ )
17
+
16
18
  render_up
17
19
  end
18
20
 
19
21
  private
20
22
 
21
- def check_good_job
22
- return if GoodJob::Process.active.count.positive?
23
-
24
- raise PgEngine::Error, 'good_job is down'
25
- end
26
-
27
- def check_postgres
28
- return if User.count.is_a? Integer
29
-
30
- raise PgEngine::Error, 'postgres is down'
31
- end
32
-
33
- def check_redis
34
- return if Kredis.counter('healthcheck').increment.is_a? Integer
35
-
36
- raise PgEngine::Error, 'redis is down'
37
- end
38
-
39
- def check_websocket
40
- result = nil
41
- begin
42
- Timeout.timeout(5) do
43
- EM.run do
44
- url = Rails.application.config.action_cable.url
45
- ws = Faye::WebSocket::Client.new(url)
46
-
47
- ws.on :message do |event|
48
- type = JSON.parse(event.data)['type']
49
- if type == 'welcome'
50
- result = :success
51
- ws.close
52
- EM.stop
53
- end
54
- end
55
- end
56
- end
57
- rescue Timeout::Error
58
- raise PgEngine::Error, 'websocket server is down'
59
- end
60
-
61
- return if result == :success
62
-
63
- raise PgEngine::Error, 'websocket server is down'
64
- end
65
- # rubocop:enable Metrics/MethodLength
66
-
67
- def check_ssl
68
- raise PgEngine::Error, 'no ssl log file' unless File.exist?(PgEngine::SslVerifier::OUTPUT_PATH)
69
-
70
- sites = JSON.parse(File.read(PgEngine::SslVerifier::OUTPUT_PATH))
71
- PgEngine.config.health_ssl_urls.each do |url|
72
- check_site_ssl(sites, url)
73
- end
74
- end
75
-
76
- def check_site_ssl(sites, url)
77
- raise PgEngine::Error, "SSL record not present: #{url}. Forgot to run PgEngine::SslVerifier ?" if sites[url].blank?
78
-
79
- if Time.zone.parse(sites[url]['verified_at']) < 2.days.ago
80
- raise PgEngine::Error, "The SSL info is outdated: #{url}. PgEngine::SslVerifier is down?"
81
- end
23
+ def parse_ary(param)
24
+ return if param.blank?
82
25
 
83
- return unless Time.zone.parse(sites[url]['expires_at']) < 7.days.from_now
26
+ ary = JSON.parse(param)
84
27
 
85
- raise PgEngine::Error, "The SSL certificate is expired (or about to expire): #{url}"
28
+ ary.is_a?(Array) ? ary : [ary]
86
29
  end
87
30
 
88
31
  def render_up
@@ -4,7 +4,8 @@
4
4
 
5
5
  module PgEngine
6
6
  class Configuracion
7
- attr_accessor :users_controller, :global_domains, :navigators, :user_profiles, :health_ssl_urls
7
+ attr_accessor :users_controller, :global_domains, :navigators,
8
+ :user_profiles, :health_ssl_urls, :health_checks
8
9
 
9
10
  # attr_accessor :profile_groups
10
11
 
@@ -12,6 +13,7 @@ module PgEngine
12
13
  @global_domains = ['app.localhost.com', 'test.host', 'localhost']
13
14
  @navigators = [PgEngine::Navigator.new]
14
15
  @health_ssl_urls = []
16
+ @health_checks = []
15
17
  # @profile_groups = [:account]
16
18
  @user_profiles = {
17
19
  account__owner: 0
@@ -55,5 +57,20 @@ module PgEngine
55
57
  { name: group, options: }
56
58
  end
57
59
  end
60
+
61
+ # @param [String] name
62
+ # description for the check
63
+ #
64
+ # @param [Duration] frequency
65
+ # interval to wait between check runs, if left blank, check will run
66
+ # every time
67
+ #
68
+ # @param [Proc] block
69
+ # a function that raises error if sth is wrong
70
+ def add_health_check(name, only_explicit: false, &block)
71
+ @health_checks.push(
72
+ { name:, only_explicit:, block: }
73
+ )
74
+ end
58
75
  end
59
76
  end
@@ -0,0 +1,117 @@
1
+ module PgEngine
2
+ class HealthChecker
3
+ def run_checks(only: nil, except: nil)
4
+ validate_check_names!(only)
5
+ validate_check_names!(except)
6
+
7
+ all_checks.each do |health_check|
8
+ included = only.present? && only.include?(health_check[:name].to_s)
9
+ excluded = except.present? && except.include?(health_check[:name].to_s)
10
+
11
+ if included || (only.blank? && !health_check[:only_explicit] && !excluded)
12
+ Rails.logger.info "Running health check: #{health_check[:name]}"
13
+
14
+ health_check[:block].call
15
+ else
16
+ Rails.logger.info "Skipping health check: #{health_check[:name]}"
17
+ end
18
+ rescue StandardError => e
19
+ raise "Health check failed: #{health_check[:name]}. With: #{e.message}", cause: e
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ def all_checks
26
+ [default_checks, PgEngine.config.health_checks].flatten
27
+ end
28
+
29
+ def validate_check_names!(checks)
30
+ return if checks.blank?
31
+
32
+ checks.each do |check|
33
+ unless all_checks.map { |chk| chk[:name].to_s }.include?(check)
34
+ raise "Check not found: #{check}"
35
+ end
36
+ end
37
+ end
38
+
39
+ def default_checks
40
+ ary = []
41
+ ary << {
42
+ name: :redis,
43
+ block: lambda do
44
+ return if Kredis.counter('healthcheck').increment.is_a? Integer
45
+
46
+ raise PgEngine::Error, 'redis is down'
47
+ end
48
+ }
49
+ ary << {
50
+ name: :postgres,
51
+ block: lambda do
52
+ return if User.count.is_a? Integer
53
+
54
+ raise PgEngine::Error, 'postgres is down'
55
+ end
56
+ }
57
+ ary << {
58
+ name: :websocket,
59
+ block: lambda do
60
+ result = nil
61
+ begin
62
+ Timeout.timeout(5) do
63
+ EM.run do
64
+ url = Rails.application.config.action_cable.url
65
+ ws = Faye::WebSocket::Client.new(url)
66
+
67
+ ws.on :message do |event|
68
+ type = JSON.parse(event.data)['type']
69
+ if type == 'welcome'
70
+ result = :success
71
+ ws.close
72
+ EM.stop
73
+ end
74
+ end
75
+ end
76
+ end
77
+ rescue Timeout::Error
78
+ raise PgEngine::Error, 'websocket server is down'
79
+ end
80
+
81
+ return if result == :success
82
+
83
+ raise PgEngine::Error, 'websocket server is down'
84
+ end
85
+ }
86
+ ary << {
87
+ name: :ssl,
88
+ block: lambda do
89
+ SslChecker.new.check_ssl
90
+ end
91
+ }
92
+ end
93
+
94
+ class SslChecker
95
+ def check_ssl
96
+ raise PgEngine::Error, 'no ssl log file' unless File.exist?(PgEngine::SslVerifier::OUTPUT_PATH)
97
+
98
+ sites = JSON.parse(File.read(PgEngine::SslVerifier::OUTPUT_PATH))
99
+ PgEngine.config.health_ssl_urls.each do |url|
100
+ check_site_ssl(sites, url)
101
+ end
102
+ end
103
+
104
+ def check_site_ssl(sites, url)
105
+ raise PgEngine::Error, "SSL record not present: #{url}. Forgot to run PgEngine::SslVerifier ?" if sites[url].blank?
106
+
107
+ if Time.zone.parse(sites[url]['verified_at']) < 2.days.ago
108
+ raise PgEngine::Error, "The SSL info is outdated: #{url}. PgEngine::SslVerifier is down?"
109
+ end
110
+
111
+ return unless Time.zone.parse(sites[url]['expires_at']) < 7.days.from_now
112
+
113
+ raise PgEngine::Error, "The SSL certificate is expired (or about to expire): #{url}"
114
+ end
115
+ end
116
+ end
117
+ end
@@ -39,6 +39,10 @@ module PgEngine
39
39
  raise PgEngine::Error, "#{url}: The SSL certificate is expired (or about to expire)."
40
40
  end
41
41
 
42
+ # FIXME: ensure domain is included in certificate domains
43
+ # for example, if domain is example.com and certificate is issued for
44
+ # *.example.com, it fails.
45
+
42
46
  log_output(url, cert.not_after)
43
47
  end
44
48
  rescue OpenSSL::SSL::SSLError => e
@@ -4,6 +4,7 @@ require_relative 'pg_engine/engine'
4
4
  require_relative 'pg_engine/core_ext'
5
5
  require_relative 'pg_engine/error'
6
6
  require_relative 'pg_engine/configuracion'
7
+ require_relative 'pg_engine/health_checker'
7
8
  require_relative 'pg_engine/site_brand'
8
9
  require_relative 'pg_engine/navigator'
9
10
  require_relative 'pg_engine/active_job_extensions'
@@ -0,0 +1,38 @@
1
+ require 'rails_helper'
2
+
3
+ describe PgEngine::HealthChecker do
4
+ let(:health_checker) { described_class.new }
5
+ let(:doub) { double }
6
+
7
+ before do
8
+ PgEngine.config.health_checks = []
9
+ end
10
+
11
+ it "checks the extras" do
12
+ allow(doub).to receive(:bla)
13
+ PgEngine.configurar do |config|
14
+ config.add_health_check(:dummy_check) do
15
+ doub.bla
16
+ end
17
+ end
18
+ health_checker.run_checks(only: ["dummy_check"])
19
+ expect(doub).to have_received(:bla)
20
+ end
21
+
22
+ it "error is descriptive" do
23
+ PgEngine.configurar do |config|
24
+ config.add_health_check(:dummy_check) do
25
+ raise "sth went wrong"
26
+ end
27
+ end
28
+ expect do
29
+ health_checker.run_checks(only: ["dummy_check"])
30
+ end.to raise_error(/Health check failed: dummy_check/)
31
+ end
32
+
33
+ it "fails if check name is wrong" do
34
+ expect do
35
+ health_checker.run_checks(only: ["wrong_check_name"])
36
+ end.to raise_error(/Check not found/)
37
+ end
38
+ end
@@ -44,10 +44,17 @@ document.addEventListener('turbo:frame-missing', async (ev) => {
44
44
 
45
45
  flashMessage(html, 'alert')
46
46
  })
47
+
48
+ // Sometimes browsers throw a "Failed to fetch" error, this is to get an
49
+ // insight into it and see if we can wrap around it for better handling
50
+ document.addEventListener('turbo:fetch-request-error', (ev) => {
51
+ Rollbar.warning('turbo:fetch-request-error', ev.detail)
52
+ console.error('turbo:fetch-request-error', ev.detail)
53
+ })
54
+
47
55
  // document.addEventListener('turbo:before-stream-render', function () { console.log('turbo:before-stream-render') })
48
56
  // document.addEventListener('turbo:render', function () { console.log('turbo:render') })
49
57
  // document.addEventListener('turbo:before-render', function () { console.log('turbo:before-render') })
50
58
  // document.addEventListener('turbo:before-frame-render', function () { console.log('turbo:before-frame-render') })
51
59
  // document.addEventListener('turbo:frame-load', function () { console.log('turbo:frame-load') })
52
60
  // document.addEventListener('turbo:before-fetch-request', function () { console.log('turbo:before-fetch-request') })
53
- // document.addEventListener('turbo:fetch-request-error', function () { console.log('turbo:fetch-request-error') })
@@ -2,6 +2,6 @@
2
2
 
3
3
  # :nocov:
4
4
  module PgRails
5
- VERSION = '7.6.46'
5
+ VERSION = '7.6.48'
6
6
  end
7
7
  # :nocov:
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pg_rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 7.6.46
4
+ version: 7.6.48
5
5
  platform: ruby
6
6
  authors:
7
7
  - Martín Rosso
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-03-20 00:00:00.000000000 Z
11
+ date: 2026-04-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -30,28 +30,28 @@ dependencies:
30
30
  requirements:
31
31
  - - '='
32
32
  - !ruby/object:Gem::Version
33
- version: 1.5.1
33
+ version: 1.6.4
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - '='
39
39
  - !ruby/object:Gem::Version
40
- version: 1.5.1
40
+ version: 1.6.4
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: anycable-rails
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: 1.5.1
47
+ version: 1.6.2
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: 1.5.1
54
+ version: 1.6.2
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: anycable-rails-jwt
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -890,6 +890,7 @@ files:
890
890
  - pg_engine/lib/pg_engine/email_observer.rb
891
891
  - pg_engine/lib/pg_engine/engine.rb
892
892
  - pg_engine/lib/pg_engine/error.rb
893
+ - pg_engine/lib/pg_engine/health_checker.rb
893
894
  - pg_engine/lib/pg_engine/mailgun/log_sync.rb
894
895
  - pg_engine/lib/pg_engine/navigator.rb
895
896
  - pg_engine/lib/pg_engine/route_helpers.rb
@@ -935,6 +936,7 @@ files:
935
936
  - pg_engine/spec/lib/pg_engine/date_jumper_spec.rb
936
937
  - pg_engine/spec/lib/pg_engine/error_helper_spec.rb
937
938
  - pg_engine/spec/lib/pg_engine/form_helper_spec.rb
939
+ - pg_engine/spec/lib/pg_engine/health_checker_spec.rb
938
940
  - pg_engine/spec/lib/pg_engine/mailgun/log_sync_spec.rb
939
941
  - pg_engine/spec/lib/pg_engine/utils/pg_engine/pg_logger_spec.rb
940
942
  - pg_engine/spec/lib/pg_engine/utils/ssl_verifier_spec.rb