process_settings 0.4.0.pre.9 → 0.4.0.pre.10

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
  SHA1:
3
- metadata.gz: a040e14386ae60b985247adceac4712bed11ee76
4
- data.tar.gz: 0cfc7cb17b53ae8f6797df32a5bd3101a2bfe115
3
+ metadata.gz: 605629bf6a5f9a31b9d46ea7b1d4ed83dc822b20
4
+ data.tar.gz: b6df3ada5eddb07783014fa9db62d02953e84238
5
5
  SHA512:
6
- metadata.gz: 7c080c469216c8dd05c7c2c4e800d0a2d39fe57effce522938367649ca7184be0f68a18a9bf55d32261f53060173530eb72c9059459c72d3b5581291ffffbdbc
7
- data.tar.gz: c1e12594b33113fb60b292033154d91bd335a121e621df5ddf8254ae3b7240c8e80d2bb653cbd59ca12d4da49f77ec81483581490fe7f803e1f6eb9d251cdce2
6
+ metadata.gz: 7ce692cc7a87d7a2c3fa8b0b8b9f42a6f37c32bc1e4871bd509a27e544272e5957e395463dc99b39b3efcd9456be8aeacee05e9559f0e9d0a227af9d222294eb
7
+ data.tar.gz: '02548c651f62448c6ed659abba25227318164fbbd327bdc1d55f01731aa5c4fe3327f1e63ae165832b4a859be564913d6043db46e06a93e168cbb6d5dbc0c9b5'
data/README.md CHANGED
@@ -1,7 +1,9 @@
1
- # ProcessSettings [![Build Status](https://travis-ci.org/Invoca/process_settings.svg?branch=master)](https://travis-ci.org/Invoca/process_settings) [![Coverage Status](https://coveralls.io/repos/github/Invoca/process_settings/badge.svg?branch=master)](https://coveralls.io/github/Invoca/process_settings?branch=master) [![Gem Version](https://badge.fury.io/rb/process_settings.svg)](https://badge.fury.io/rb/process_settings)
2
- This gem provides dynamic settings for Linux processes. These settings are stored in JSON.
3
- They including a targeting notation so that each settings group can be targeted based on matching context values.
4
- The context can be either static to the process (for example, service_name or data_center) or dynamic (for example, the domain of the current web request).
1
+ # ProcessSettings
2
+ This gem provides dynamic settings for Ruby processes. The settings are stored in YAML.
3
+ Settings are managed in a git repo, in separate YAML files for each concern (for example, each micro-service). Each YAML file can be targeted based on matching context values (for example, `service_name`).
4
+
5
+
6
+ The context can be either static to the process (for example, `service_name` or `data_center`) or dynamic (for example, the current web request `domain`).
5
7
 
6
8
  ## Installation
7
9
  To install this gem directly on your machine from rubygems, run the following:
@@ -11,27 +13,151 @@ gem install process_settings
11
13
 
12
14
  To install this gem in your bundler project, add the following to your Gemfile:
13
15
  ```ruby
14
- gem 'process_settings', '~> 0.3'
15
- ```
16
-
17
- To use an unreleased version, add it to your Gemfile for Bundler:
18
- ```ruby
19
- gem 'process_settings', git: 'git@github.com:Invoca/process_settings'
16
+ gem 'process_settings', '~> 0.4'
20
17
  ```
21
18
 
22
19
  ## Usage
23
- ### Initialization
24
- To use the contextual logger, all you need to do is initailize the object with your existing logger
20
+ The `ProcessSettings::Monitor` and related classes can be freely created and used at any time.
21
+ But typical usage is through the `ProcessSettings::Monitor.instance`.
22
+ That should be configured at process startup before use.
23
+ ### Configuration
24
+ Before using `ProcessSettings::Monitor.instance`, you must first configure the path to the combined process settings file on disk,
25
+ and provide a logger.
25
26
  ```ruby
26
27
  require 'process_settings'
28
+
29
+ ProcessSettings::Monitor.file_path = "/etc/process_settings/combined_process_settings.yml"
30
+ ProcessSettings::Monitor.logger = logger
31
+ ```
32
+ ### Monitor Initialization
33
+ The `ProcessSettings::Monitor` is a hybrid singleton. The class attribute `instance` returns
34
+ the current instance. If not already set, this is lazy-created based on the above configuration.
35
+
36
+ The monitor should be initialized with static (unchanging) context for your process:
37
+ ```
38
+ ProcessSettings::Monitor.static_context = {
39
+ "service_name" => "frontend",
40
+ "data_center" => "AWS-US-EAST-1"
41
+ }
42
+ ```
43
+ The `static_context` is important because it is used to pre-filter settings for the process.
44
+ For example, a setting that is targeted to `service_name: frontend` will match the above static context and
45
+ be simplified to `true`. In other processes with a different `service_name`, such a targeted setting will be
46
+ simplified to `false` and removed from memory.
47
+
48
+ Note that the `static_context` as well as `dynamic_context` must use strings, not symbols, for both keys and values.
49
+
50
+ ### Reading Settings
51
+ For the following section, consider this `combined_process_settings.yml` file:
52
+ ```
53
+ ---
54
+ - filename: frontend.yml
55
+ settings:
56
+ frontend:
57
+ log_level: info
58
+ - filename: frontend-microsite.yml
59
+ target:
60
+ domain: microsite.example.com
61
+ settings:
62
+ frontend:
63
+ log_level: debug
64
+ - meta:
65
+ version: 27
66
+ END: true
67
+ ```
68
+
69
+ To read a setting, application code should call the `[]` method on the `ProcessSettings` class. For example:
70
+ ```
71
+ log_level = ProcessSettings['frontend', 'log_level']
72
+ => "info"
73
+ ```
74
+ #### ProcessSettings[] interface
75
+ The `ProcessSettings[]` method delegates to `ProcessSettings::Monitor#[]` on the `instance`.
76
+
77
+ `[]` interface:
78
+
79
+ ```
80
+ [](*path, dynamic_context: {}, required: true)
81
+ ```
82
+
83
+ |argument|description|
84
+ |--------|-------------|
85
+ |_path_ |A series of 1 or more comma-separated strings forming a path to navigate the `settings` hash, starting at the top.|
86
+ |`dynamic_context:` |An optional hash of dynamic settings, used to target the settings. This will automatically be deep-merged with the static context. It may not contradict the static context. |
87
+ |`required:` |A boolean indicating if the setting is required to be present. If a setting is missing, then if `required` is truthy, a `ProcesssSettings::SettingsPathNotFound` exception will be raised. Otherwise, `nil` will be returned. Default: `true`.
88
+
89
+ Example with `dynamic_context`:
90
+ ```
91
+ log_level = ProcessSettings['frontend', 'log_level',
92
+ dynamic_context: { "domain" => "microsite.example.com" }
93
+ ]
94
+ => "debug"
27
95
  ```
28
96
 
29
- TODO: Fill in here how to use the Monitor's instance method to get current settings, how to register for on_change callbacks, etc.
97
+ Example with `required: true` (default) that was not found:
98
+ ```
99
+ http_version = ProcessSettings['frontend', 'http_version']
100
+
101
+ exception raised!
102
+
103
+ ProcessSettings::SettingsPathNotFound: No settings found for path ["frontend", "http_version"]
104
+ ```
105
+
106
+ Here is the same example with `required: false`, applying a default value of `2`:
107
+ ```
108
+ http_version = ProcessSettings['frontend', 'http_version', required: false] || 2
109
+ ```
30
110
 
31
111
  ### Dynamic Settings
32
112
 
33
- In order to load changes dynamically, `ProcessSettings` relies on INotify module of the Linux kernel. On kernels that do not have this module (MacOS for example), you will see a warning on STDERR that changes will not be loaded while the process runs.
113
+ The `ProcessSettings::Monitor` loads settings changes dynamically whenever the file changes,
114
+ by using the [listen](https://github.com/guard/listen) gem which in turn uses the `INotify` module of the Linux kernel, or `FSEvents` on MacOS. There is no need to restart the process or send it a signal to tell it to reload changes.
115
+
116
+ There are two ways to get access the latest settings from inside the process:
117
+
118
+ #### Read Latest Setting Through `ProcessSettings[]`
119
+
120
+ The simplest approach--as shown above--is to read the latest settings at any time through `ProcessSettings[]` (which delegates to `ProcessSettings::Monitor.instance`):
121
+ ```
122
+ http_version = ProcessSettings['frontend', 'http_version']
123
+ ```
124
+
125
+ #### Register an `on_change` Callback
126
+ Alternatively, if you need to execute some code when there is a change, register a callback with `ProcessSettings::Monitor#on_change`:
127
+ ```
128
+ ProcessSettings::Monitor.instance.on_change do
129
+ logger.level = ProcessSettings['frontend', 'log_level']
130
+ end
131
+ ```
132
+ Note that all callbacks run sequentially on the shared change monitoring thread, so please be considerate!
133
+
134
+ There is no provision for unregistering callbacks. Instead, replace the `instance` of the monitor with a new one.
135
+
136
+ ## Targeting
137
+ Each settings YAML file has an optional `target` key at the top level, next to `settings`.
138
+
139
+ If there is no `target` key, the target defaults to `true`, meaning all processes are targeted for these settings. (However, the settings may be overridden by other YAML files. See "Precedence" below.)
140
+
141
+ ### Hash Key-Values Are AND'd
142
+ To `target` on context values, provide a hash of key-value pairs. All keys must match for the target to be met. For example, consider this target hash:
143
+ ```
144
+ target:
145
+ service_name: frontend
146
+ data_center: AWS-US-EAST-1
147
+ ```
148
+ This will be applied in any process that has `service_name == "frontend"` AND is running in `data_center == "AWS-US-EAST-1"`.
149
+
150
+ ### Multiple Values Are OR'd
151
+ Values may be set to an array, in which case the key matches if _any_ of the values matches. For example, consider this target hash:
152
+ ```
153
+ target:
154
+ service_name: [frontend, auth]
155
+ data_center: AWS-US-EAST-1
156
+ ```
157
+ This will be applied in any process that has (`service_name == "frontend"` OR `service_name == "auth"`) AND `data_center == "AWS-US-EAST-1"`.
34
158
 
159
+ ### Precedence
160
+ The settings YAML files are always combined in alphabetical order by file path. Later settings take precedence over the earlier ones.
35
161
 
36
162
  ## Contributions
37
163
 
@@ -32,15 +32,16 @@ def parse_options(argv)
32
32
  options.verbose = false
33
33
  option_parser = OptionParser.new(argv) do |opt|
34
34
  opt.on('-v', '--verbose', 'Verbose mode.') { options.verbose = true }
35
+ opt.on('-n', '--version=VERSION', 'Set version number.') { |value| options.version = value.to_i }
35
36
  opt.on('-r', '--root_folder=ROOT') { |o| options.root_folder = o }
36
37
  opt.on('-o', '--output=FILENAME', 'Output file.') { |o| options.output_filename = o }
37
38
  opt.on('-i', '--initial=FILENAME', 'Initial settings file for version inference.') { |o| options.initial_filename = o }
38
39
  end
39
40
 
40
- if option_parser.parse! && options.root_folder && options.output_filename && (ENV['BUILD_NUMBER'] || options.initial_filename)
41
+ if option_parser.parse! && options.root_folder && options.output_filename && (options.version || options.initial_filename)
41
42
  options
42
43
  else
43
- warn "usage: #{PROGRAM_NAME} -r staging|production -o combined_process_settings.yml [-i initial_combined_process_settings.yml] (required if BUILD_NUMBER not set)"
44
+ warn "usage: #{PROGRAM_NAME} -r staging|production -o combined_process_settings.yml [--version=VERSION] [-i initial_combined_process_settings.yml] (-i required if --version= not set)"
44
45
  option_parser.summarize(STDERR)
45
46
  exit(1)
46
47
  end
@@ -82,7 +83,7 @@ options = parse_options(ARGV.dup)
82
83
 
83
84
  combined_settings = read_and_combine_settings(Pathname.new(options.root_folder) + SETTINGS_FOLDER)
84
85
 
85
- version_number = ENV['BUILD_NUMBER']&.to_i || default_version_number(options.initial_filename)
86
+ version_number = options.version || default_version_number(options.initial_filename)
86
87
  combined_settings << end_marker(version_number)
87
88
 
88
89
  yaml = combined_settings.to_yaml
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ProcessSettings
4
- VERSION = '0.4.0.pre.9'
4
+ VERSION = '0.4.0.pre.10'
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.4.0.pre.9
4
+ version: 0.4.0.pre.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Invoca