diff --git a/README.md b/README.md index 1923b31d..77722ab0 100644 --- a/README.md +++ b/README.md @@ -44,9 +44,9 @@ It is **required** to configure: Please substitute the example `'https://unleash.herokuapp.com/api'` for the url of your own instance. -### instance_id +It is **highly recommended** to configure: +- `instance_id` parameter with a unique identifier for the running instance. -As of version 5.0.3, `instance_id` is now an automatically generated read-only property. ```ruby Unleash.configure do |config| @@ -84,6 +84,7 @@ Argument | Description | Required? | Type | Default Value| ---------|-------------|-----------|-------|---------------| `url` | Unleash server URL. | Y | String | N/A | `app_name` | Name of your program. | Y | String | N/A | +`instance_id` | Identifier for the running instance of program. Important so you can trace back to where metrics are being collected from. **Highly recommended be be set.** | N | String | random UUID | `environment` | Unleash context option. Could be for example `prod` or `dev`. Not yet in use. **Not** the same as the SDK's [Unleash environment](https://docs.getunleash.io/reference/environments). | N | String | `default` | `project_name` | Name of the project to retrieve features from. If not set, all feature flags will be retrieved. | N | String | nil | `refresh_interval` | How often the unleash client should check with the server for configuration changes. | N | Integer | 15 | @@ -141,6 +142,7 @@ Put in `config/initializers/unleash.rb`: Unleash.configure do |config| config.app_name = Rails.application.class.parent.to_s config.url = 'https://unleash.herokuapp.com/api' + # config.instance_id = "#{Socket.gethostname}" config.logger = Rails.logger end @@ -149,6 +151,10 @@ UNLEASH = Unleash::Client.new # Or if preferred: # Rails.configuration.unleash = Unleash::Client.new ``` +For `config.instance_id` use a string with a unique identification for the running instance. +For example: it could be the hostname, if you only run one App per host. +Or the docker container id, if you are running in docker. +If it is not set the client will generate an unique UUID for each execution. To have it available in the `rails console` command as well, also add to the file above: ```ruby @@ -242,6 +248,7 @@ PhusionPassenger.on_event(:starting_worker_process) do |forked| if forked Unleash.configure do |config| config.app_name = Rails.application.class.parent.to_s + # config.instance_id = "#{Socket.gethostname}" config.logger = Rails.logger config.url = 'https://unleash.herokuapp.com/api' config.custom_http_headers = {'Authorization': ''} diff --git a/examples/bootstrap.rb b/examples/bootstrap.rb index 5a775b15..b72c94dc 100755 --- a/examples/bootstrap.rb +++ b/examples/bootstrap.rb @@ -10,6 +10,7 @@ url: 'https://unleash.herokuapp.com/api', custom_http_headers: { 'Authorization': '943ca9171e2c884c545c5d82417a655fb77cec970cc3b78a8ff87f4406b495d0' }, app_name: 'bootstrap-test', + instance_id: 'local-test-cli', refresh_interval: 2, disable_client: true, disable_metrics: true, diff --git a/examples/simple.rb b/examples/simple.rb index f8995f61..4d74d0d6 100755 --- a/examples/simple.rb +++ b/examples/simple.rb @@ -21,6 +21,7 @@ url: 'https://unleash.herokuapp.com/api', custom_http_headers: { 'Authorization': '943ca9171e2c884c545c5d82417a655fb77cec970cc3b78a8ff87f4406b495d0' }, app_name: 'simple-test', + instance_id: 'local-test-cli', refresh_interval: 2, metrics_interval: 2, retry_limit: 2 diff --git a/lib/unleash/configuration.rb b/lib/unleash/configuration.rb index d1afdec9..fb3dd382 100644 --- a/lib/unleash/configuration.rb +++ b/lib/unleash/configuration.rb @@ -8,6 +8,7 @@ class Configuration :url, :app_name, :environment, + :instance_id, :project_name, :custom_http_headers, :disable_client, @@ -22,15 +23,10 @@ class Configuration :bootstrap_config, :strategies - attr_reader \ - :instance_id - def initialize(opts = {}) validate_custom_http_headers!(opts[:custom_http_headers]) if opts.has_key?(:custom_http_headers) set_defaults - @instance_id = SecureRandom.uuid - initialize_default_logger if opts[:logger].nil? merge(opts) @@ -90,6 +86,7 @@ def set_defaults self.app_name = nil self.environment = 'default' self.url = nil + self.instance_id = SecureRandom.uuid self.project_name = nil self.disable_client = false self.disable_metrics = false diff --git a/spec/unleash/bootstrap/handler_spec.rb b/spec/unleash/bootstrap/handler_spec.rb index 01d691da..4e31d184 100644 --- a/spec/unleash/bootstrap/handler_spec.rb +++ b/spec/unleash/bootstrap/handler_spec.rb @@ -5,6 +5,7 @@ Unleash.configure do |config| config.url = 'http://unleash-url/' config.app_name = 'my-test-app' + config.instance_id = 'rspec/test' config.custom_http_headers = { 'X-API-KEY' => '123' } end diff --git a/spec/unleash/client_spec.rb b/spec/unleash/client_spec.rb index 9b9c074e..814efbe1 100644 --- a/spec/unleash/client_spec.rb +++ b/spec/unleash/client_spec.rb @@ -45,6 +45,7 @@ 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Content-Type' => 'application/json', 'Unleash-Appname' => 'my-test-app', + 'Unleash-Instanceid' => 'rspec/test', 'User-Agent' => "UnleashClientRuby/#{Unleash::VERSION} #{RUBY_ENGINE}/#{RUBY_VERSION} [#{RUBY_PLATFORM}]", 'X-Api-Key' => '123' } @@ -54,12 +55,14 @@ Unleash.configure do |config| config.url = 'http://test-url/' config.app_name = 'my-test-app' + config.instance_id = 'rspec/test' config.custom_http_headers = { 'X-API-KEY' => '123' } end unleash_client = Unleash::Client.new( url: 'http://test-url/', app_name: 'my-test-app', + instance_id: 'rspec/test', custom_http_headers: { 'X-API-KEY' => '123' } ) @@ -70,14 +73,14 @@ .with(headers: { 'Content-Type': 'application/json' }) .with(headers: { 'X-API-KEY': '123', 'Content-Type': 'application/json' }) .with(headers: { 'UNLEASH-APPNAME': 'my-test-app' }) - .with(headers: { 'UNLEASH-INSTANCEID': Unleash.configuration.instance_id }) + .with(headers: { 'UNLEASH-INSTANCEID': 'rspec/test' }) ).to have_been_made.once expect( a_request(:get, "http://test-url/client/features") .with(headers: { 'X-API-KEY': '123' }) .with(headers: { 'UNLEASH-APPNAME': 'my-test-app' }) - .with(headers: { 'UNLEASH-INSTANCEID': Unleash.configuration.instance_id }) + .with(headers: { 'UNLEASH-INSTANCEID': 'rspec/test' }) ).to have_been_made.once # Test now sending of metrics @@ -88,7 +91,7 @@ .with(headers: { 'Content-Type': 'application/json' }) .with(headers: { 'X-API-KEY': '123', 'Content-Type': 'application/json' }) .with(headers: { 'UNLEASH-APPNAME': 'my-test-app' }) - .with(headers: { 'UNLEASH-INSTANCEID': Unleash.configuration.instance_id }) + .with(headers: { 'UNLEASH-INSTANCEID': 'rspec/test' }) ).not_to have_been_made # Sending metrics, if they have been evaluated: @@ -100,7 +103,7 @@ .with(headers: { 'Content-Type': 'application/json' }) .with(headers: { 'X-API-KEY': '123', 'Content-Type': 'application/json' }) .with(headers: { 'UNLEASH-APPNAME': 'my-test-app' }) - .with(headers: { 'UNLEASH-INSTANCEID': Unleash.configuration.instance_id }) + .with(headers: { 'UNLEASH-INSTANCEID': 'rspec/test' }) .with{ |request| JSON.parse(request.body)['bucket']['toggles']['Feature.A']['yes'] == 2 } ).to have_been_made.once end @@ -113,7 +116,7 @@ 'Content-Type' => 'application/json', 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Unleash-Appname' => 'my-test-app', - 'Unleash-Instanceid' => Unleash.configuration.instance_id, + 'Unleash-Instanceid' => 'rspec/test', 'User-Agent' => "UnleashClientRuby/#{Unleash::VERSION} #{RUBY_ENGINE}/#{RUBY_VERSION} [#{RUBY_PLATFORM}]", 'X-Api-Key' => '123' } @@ -154,7 +157,7 @@ 'Content-Type' => 'application/json', 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Unleash-Appname' => 'my-test-app', - 'Unleash-Instanceid' => Unleash.configuration.instance_id, + 'Unleash-Instanceid' => 'rspec/test', 'User-Agent' => "UnleashClientRuby/#{Unleash::VERSION} #{RUBY_ENGINE}/#{RUBY_VERSION} [#{RUBY_PLATFORM}]", 'X-Api-Key' => '123' } @@ -164,6 +167,7 @@ Unleash.configure do |config| config.url = 'http://test-url/' config.app_name = 'my-test-app' + config.instance_id = 'rspec/test' config.disable_metrics = true config.custom_http_headers = { 'X-API-KEY' => '123' } config.log_level = Logger::DEBUG @@ -212,6 +216,7 @@ Unleash.configure do |config| config.url = 'http://test-url/' config.app_name = 'my-test-app' + config.instance_id = 'rspec/test' config.disable_client = true config.disable_metrics = true config.custom_http_headers = { 'X-API-KEY' => '123' } @@ -264,7 +269,7 @@ 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Content-Type' => 'application/json', 'Unleash-Appname' => 'my-test-app', - 'Unleash-Instanceid' => Unleash.configuration.instance_id, + 'Unleash-Instanceid' => 'rspec/test', 'User-Agent' => "UnleashClientRuby/#{Unleash::VERSION} #{RUBY_ENGINE}/#{RUBY_VERSION} [#{RUBY_PLATFORM}]", 'X-Api-Key' => '123' } @@ -274,6 +279,7 @@ Unleash.configure do |config| config.url = 'http://test-url/' config.app_name = 'my-test-app' + config.instance_id = 'rspec/test' config.disable_client = false config.disable_metrics = true config.custom_http_headers = { 'X-API-KEY' => '123' } @@ -321,7 +327,7 @@ 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Content-Type' => 'application/json', 'Unleash-Appname' => 'my-test-app', - 'Unleash-Instanceid' => Unleash.configuration.instance_id, + 'Unleash-Instanceid' => 'rspec/test', 'User-Agent' => "UnleashClientRuby/#{Unleash::VERSION} #{RUBY_ENGINE}/#{RUBY_VERSION} [#{RUBY_PLATFORM}]", 'X-Api-Key' => '123' } @@ -331,6 +337,7 @@ Unleash.configure do |config| config.url = 'http://test-url/' config.app_name = 'my-test-app' + config.instance_id = 'rspec/test' config.disable_client = false config.disable_metrics = true config.custom_http_headers = { 'X-API-KEY' => '123' } @@ -350,6 +357,7 @@ Unleash.configure do |config| config.url = 'http://test-url/' config.app_name = 'my-test-app' + config.instance_id = 'rspec/test' config.disable_client = true config.disable_metrics = false config.custom_http_headers = { 'X-API-KEY' => '123' } @@ -597,7 +605,7 @@ 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Content-Type' => 'application/json', 'Unleash-Appname' => 'my-test-app', - 'Unleash-Instanceid' => Unleash.configuration.instance_id, + 'Unleash-Instanceid' => 'rspec/test', 'User-Agent' => "UnleashClientRuby/#{Unleash::VERSION} #{RUBY_ENGINE}/#{RUBY_VERSION} [#{RUBY_PLATFORM}]", 'X-Api-Key' => '123' } @@ -611,7 +619,7 @@ 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Content-Type' => 'application/json', 'Unleash-Appname' => 'my-test-app', - 'Unleash-Instanceid' => Unleash.configuration.instance_id, + 'Unleash-Instanceid' => 'rspec/test', 'User-Agent' => "UnleashClientRuby/#{Unleash::VERSION} #{RUBY_ENGINE}/#{RUBY_VERSION} [#{RUBY_PLATFORM}]", 'X-Api-Key' => '123' } diff --git a/spec/unleash/metrics_reporter_spec.rb b/spec/unleash/metrics_reporter_spec.rb index 2fb95cf2..b8aed969 100644 --- a/spec/unleash/metrics_reporter_spec.rb +++ b/spec/unleash/metrics_reporter_spec.rb @@ -13,6 +13,7 @@ Unleash.configuration.url = 'http://test-url/' Unleash.configuration.app_name = 'my-test-app' + Unleash.configuration.instance_id = 'rspec/test' # Do not test the scheduled calls from client/metrics: Unleash.configuration.disable_client = true @@ -23,6 +24,7 @@ Unleash.configure do |config| config.url = 'http://test-url/' config.app_name = 'my-test-app' + config.instance_id = 'rspec/test' config.disable_client = true end Unleash.toggle_metrics = Unleash::Metrics.new @@ -66,7 +68,7 @@ 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Content-Type' => 'application/json', 'Unleash-Appname' => 'my-test-app', - 'Unleash-Instanceid' => Unleash.configuration.instance_id, + 'Unleash-Instanceid' => 'rspec/test', 'User-Agent' => "UnleashClientRuby/#{Unleash::VERSION} #{RUBY_ENGINE}/#{RUBY_VERSION} [#{RUBY_PLATFORM}]" } ) @@ -97,7 +99,7 @@ .with( body: hash_including( appName: "my-test-app", - instanceId: Unleash.configuration.instance_id + instanceId: "rspec/test" ) ) end diff --git a/spec/unleash/scheduled_executor_spec.rb b/spec/unleash/scheduled_executor_spec.rb index b11828f7..4337581f 100644 --- a/spec/unleash/scheduled_executor_spec.rb +++ b/spec/unleash/scheduled_executor_spec.rb @@ -35,18 +35,18 @@ max_exceptions = 1 scheduled_executor = Unleash::ScheduledExecutor.new('TesterLoop', 0, max_exceptions) - new_app_name = SecureRandom.uuid - original_app_name = Unleash.configuration.app_name + new_instance_id = SecureRandom.uuid + original_instance_id = Unleash.configuration.instance_id scheduled_executor.run do - Unleash.configuration.app_name = new_app_name + Unleash.configuration.instance_id = new_instance_id raise StopIteration end scheduled_executor.thread.join - expect(Unleash.configuration.app_name).to eq(new_app_name) + expect(Unleash.configuration.instance_id).to eq(new_instance_id) - Unleash.configuration.app_name = original_app_name + Unleash.configuration.instance_id = original_instance_id end # These two tests are super flaky because they're checking if threading works @@ -55,39 +55,39 @@ max_exceptions = 1 scheduled_executor = Unleash::ScheduledExecutor.new('TesterLoop', 0.02, max_exceptions, true) - new_app_name = SecureRandom.uuid - original_app_name = Unleash.configuration.app_name + new_instance_id = SecureRandom.uuid + original_instance_id = Unleash.configuration.instance_id scheduled_executor.run do - Unleash.configuration.app_name = new_app_name + Unleash.configuration.instance_id = new_instance_id raise StopIteration end sleep 0.01 - expect(Unleash.configuration.app_name).to eq(new_app_name) + expect(Unleash.configuration.instance_id).to eq(new_instance_id) scheduled_executor.thread.join - Unleash.configuration.app_name = original_app_name + Unleash.configuration.instance_id = original_instance_id end xit "will not trigger immediate exection when not set" do max_exceptions = 1 scheduled_executor = Unleash::ScheduledExecutor.new('TesterLoop', 0.02, max_exceptions, false) - new_app_name = SecureRandom.uuid - original_app_name = Unleash.configuration.app_name + new_instance_id = SecureRandom.uuid + original_instance_id = Unleash.configuration.instance_id scheduled_executor.run do - Unleash.configuration.app_name = new_app_name + Unleash.configuration.instance_id = new_instance_id raise StopIteration end sleep 0.01 - expect(Unleash.configuration.app_name).to eq(original_app_name) + expect(Unleash.configuration.instance_id).to eq(original_instance_id) scheduled_executor.thread.join - Unleash.configuration.app_name = original_app_name + Unleash.configuration.instance_id = original_instance_id end end