process_settings 0.16.0 → 0.19.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: fe4e35a75d3c8a06396dbc7094874cf5e2509847f66c442ff5297e9c8011cebd
4
- data.tar.gz: a7b18e595bde05fd56037570a80008bf3f0cc5d679810dce724a63977fec9a02
3
+ metadata.gz: 14973d0d1a4eb5ad4641db115a9eb439740761bbc4ae0bfd20a103a455c9eb82
4
+ data.tar.gz: 4d662530770cd4afba5792ec603c67f86681300d8aef0c4ed8d9b9e0d8975bca
5
5
  SHA512:
6
- metadata.gz: 3f972dcfa9f6e7f988866ac290e71231f0a005842105a284e6a688123e74f9e970ec60749675d0855b47d13d344462169f29cd70b7251b799ae6a6ef4f82b6a6
7
- data.tar.gz: e30ad37d7c7508c70471c75322ffcf98c981fb54bdf0e339e6ab512d95c04a8bcd2dad5917381c0a2fbd3ce468e1f04cc18bc0c7919bc9848be3f8b934155853
6
+ metadata.gz: 010056e43ab73c0a6838732c25fc4f23fcb598056cac740e81d27f5d9765b12740a1db2f587286d716613597393d49e9781150ff7bd186363c22fd0bc8b420c2
7
+ data.tar.gz: 4784757b38d3e80c41ec366ecccc0425069820a712e995927a82fffd02f177e3053cf274886259310d472cc314cdf526b8198531f965b15b24b89b520e14c612
data/README.md CHANGED
@@ -167,6 +167,32 @@ This will be applied in any process that has (`service_name == "frontend"` OR `s
167
167
  ### Precedence
168
168
  The settings YAML files are always combined in alphabetical order by file path. Later settings take precedence over the earlier ones.
169
169
 
170
+ ### Forked Processes
171
+ When using `ProcessSettings` within an environment that is forking threads (like `unicorn` web servers), you can restart the `FileMonitor`
172
+ after the fork with `restart_after_fork`.
173
+ ```ruby
174
+ # unicorn.rb
175
+
176
+ preload_app true
177
+
178
+ after_fork do
179
+ ProcessSettings.instance.restart_after_fork
180
+ end
181
+ ```
182
+
183
+ ### Start Watchdog
184
+ When using `ProcessSettings` you can start a watchdog thread using `start_watchdog_thread` on a particular file path. The watchdog will poll once a minute to double-check if any changes have been missed due to a bug in the `listen` gem or the supporting OS drivers like `inotify`.
185
+ You may not start the watchdog thread it has already been started.
186
+ ```ruby
187
+ ProcessSettings.instance.start_watchdog_thread(file_path)
188
+ ```
189
+
190
+ ### Stop Watchdog
191
+ When using `ProcessSettings` you can stop a watchdog thread using `stop_watchdog_thread`. Once stopped you may start a new watchdog thread.
192
+ ```ruby
193
+ ProcessSettings.instance.stop_watchdog_thread
194
+ ```
195
+
170
196
  ### Testing
171
197
  For testing, it is often necessary to set a specific override hash for the process_settings values to use in
172
198
  that use case. The `ProcessSettings::Testing::RSpec::Helpers` and `ProcessSettings::Testing::Minitest::Helpers` modules are provided for this purpose.
@@ -114,7 +114,11 @@ module ProcessSettings
114
114
  # find last value from matching targets
115
115
  if target_and_settings.target.target_key_matches?(full_context)
116
116
  if (value = target_and_settings.settings.json_doc.mine(*path, not_found_value: :not_found)) != :not_found
117
- latest_result = value
117
+ latest_result = if latest_result.is_a?(Hash) && value.is_a?(Hash)
118
+ latest_result.deep_merge(value)
119
+ else
120
+ value
121
+ end
118
122
  end
119
123
  end
120
124
  latest_result
@@ -8,6 +8,7 @@ require 'active_support/deprecation'
8
8
  require 'process_settings/abstract_monitor'
9
9
  require 'process_settings/targeted_settings'
10
10
  require 'process_settings/hash_path'
11
+ require 'process_settings/helpers/watchdog'
11
12
 
12
13
  module ProcessSettings
13
14
  class FileMonitor < AbstractMonitor
@@ -24,10 +25,32 @@ module ProcessSettings
24
25
  start_internal(enable_listen_thread?(environment))
25
26
  end
26
27
 
28
+ def start_watchdog_thread(file_path)
29
+ @watchdog_thread and raise ArgumentError, "watchdog thread already running!"
30
+ @watchdog_thread = Thread.new do
31
+ watchdog = Watchdog.new(file_path)
32
+ loop do
33
+ sleep(1.minute)
34
+ watchdog.check
35
+ rescue => ex
36
+ logger.error("ProcessSettings::Watchdog thread: #{ex.class.name}: #{ex.message}")
37
+ end
38
+ end
39
+ end
40
+
41
+ def stop_watchdog_thread
42
+ @watchdog_thread&.kill
43
+ @watchdog_thread = nil
44
+ end
45
+
27
46
  def start
28
47
  start_internal(enable_listen_thread?)
29
48
  end
30
- deprecate :start, deprecator: ActiveSupport::Deprecation.new('1.0', 'ProcessSettings') # will become private
49
+ deprecate start: :restart_after_fork, deprecator: ActiveSupport::Deprecation.new('1.0', 'ProcessSettings')
50
+
51
+ def restart_after_fork
52
+ start_internal(enable_listen_thread?)
53
+ end
31
54
 
32
55
  def listen_thread_running?
33
56
  !@listener.nil?
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support/core_ext/numeric/time'
4
+
5
+ module ProcessSettings
6
+ class Watchdog
7
+ class OutOfSync < StandardError; end
8
+
9
+ MAX_MTIME_DIFFERENCE = 2.minutes
10
+
11
+ def initialize(process_settings_file_path)
12
+ @process_settings_file_path = process_settings_file_path or raise ArgumentError, "process_settings_file_path must be passed"
13
+ end
14
+
15
+ def check
16
+ if version_from_memory != version_from_disk && (Time.now - mtime_from_disk) > MAX_MTIME_DIFFERENCE
17
+ raise ProcessSettings::OutOfSync.new("ProcessSettings versions are out of sync!\n Version from Disk: #{version_from_disk}\n Version from Memory: #{version_from_memory}\n mtime of file: #{mtime_from_disk}")
18
+ end
19
+ end
20
+
21
+ private
22
+
23
+ attr_reader :process_settings_file_path
24
+
25
+ def version_from_memory
26
+ ProcessSettings.instance.untargeted_settings.version
27
+ end
28
+
29
+ def version_from_disk
30
+ ProcessSettings::TargetedSettings.from_file(process_settings_file_path, only_meta: true).version
31
+ end
32
+
33
+ def mtime_from_disk
34
+ File.mtime(process_settings_file_path)
35
+ end
36
+ end
37
+ end
@@ -46,7 +46,7 @@ module ProcessSettings
46
46
  def logger=(new_logger)
47
47
  ActiveSupport::Deprecation.warn("ProcessSettings::Monitor.logger is deprecated and will be removed in v1.0.")
48
48
  @logger = new_logger
49
- Listen.logger ||= new_logger
49
+ Listen.logger = new_logger unless Listen.instance_variable_get(:@logger)
50
50
  end
51
51
 
52
52
  deprecate :logger, :logger=, :file_path, :file_path=, deprecator: ActiveSupport::Deprecation.new('1.0', 'ProcessSettings')
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ProcessSettings
4
- VERSION = '0.16.0'
4
+ VERSION = '0.19.0'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: process_settings
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.16.0
4
+ version: 0.19.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Invoca
@@ -94,6 +94,7 @@ files:
94
94
  - lib/process_settings/file_monitor.rb
95
95
  - lib/process_settings/hash_path.rb
96
96
  - lib/process_settings/hash_with_hash_path.rb
97
+ - lib/process_settings/helpers/watchdog.rb
97
98
  - lib/process_settings/monitor.rb
98
99
  - lib/process_settings/replace_versioned_file.rb
99
100
  - lib/process_settings/settings.rb