File: client.rb

package info (click to toggle)
ruby-unleash 3.2.5-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 252 kB
  • sloc: ruby: 1,098; makefile: 10; sh: 4
file content (155 lines) | stat: -rw-r--r-- 5,332 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
require 'unleash/configuration'
require 'unleash/toggle_fetcher'
require 'unleash/metrics_reporter'
require 'unleash/scheduled_executor'
require 'unleash/feature_toggle'
require 'unleash/util/http'
require 'logger'
require 'time'

module Unleash
  class Client
    attr_accessor :fetcher_scheduled_executor, :metrics_scheduled_executor

    def initialize(*opts)
      Unleash.configuration ||= Unleash::Configuration.new(*opts)
      Unleash.configuration.validate!

      Unleash.logger = Unleash.configuration.logger.clone
      Unleash.logger.level = Unleash.configuration.log_level

      if Unleash.configuration.disable_client
        Unleash.logger.warn "Unleash::Client is disabled! Will only return default results!"
        return
      end

      register
      start_toggle_fetcher
      start_metrics unless Unleash.configuration.disable_metrics
    end

    def is_enabled?(feature, context = nil, default_value = false)
      Unleash.logger.debug "Unleash::Client.is_enabled? feature: #{feature} with context #{context}"

      if Unleash.configuration.disable_client
        Unleash.logger.warn "unleash_client is disabled! Always returning #{default_value} for feature #{feature}!"
        return default_value
      end

      toggle_as_hash = Unleash&.toggles&.select{ |toggle| toggle['name'] == feature }&.first

      if toggle_as_hash.nil?
        Unleash.logger.debug "Unleash::Client.is_enabled? feature: #{feature} not found"
        return default_value
      end

      toggle = Unleash::FeatureToggle.new(toggle_as_hash)

      toggle.is_enabled?(context, default_value)
    end

    # enabled? is a more ruby idiomatic method name than is_enabled?
    alias enabled? is_enabled?

    # execute a code block (passed as a parameter), if is_enabled? is true.
    def if_enabled(feature, context = nil, default_value = false, &blk)
      yield(blk) if is_enabled?(feature, context, default_value)
    end

    def get_variant(feature, context = nil, fallback_variant = nil)
      Unleash.logger.debug "Unleash::Client.get_variant for feature: #{feature} with context #{context}"

      if Unleash.configuration.disable_client
        Unleash.logger.debug "unleash_client is disabled! Always returning #{fallback_variant} for feature #{feature}!"
        return fallback_variant || Unleash::FeatureToggle.disabled_variant
      end

      toggle_as_hash = Unleash&.toggles&.select{ |toggle| toggle['name'] == feature }&.first

      if toggle_as_hash.nil?
        Unleash.logger.debug "Unleash::Client.get_variant feature: #{feature} not found"
        return fallback_variant || Unleash::FeatureToggle.disabled_variant
      end

      toggle = Unleash::FeatureToggle.new(toggle_as_hash)
      variant = toggle.get_variant(context, fallback_variant)

      if variant.nil?
        Unleash.logger.debug "Unleash::Client.get_variant variants for feature: #{feature} not found"
        return fallback_variant || Unleash::FeatureToggle.disabled_variant
      end

      # TODO: Add to README: name, payload, enabled (bool)

      variant
    end

    # safe shutdown: also flush metrics to server and toggles to disk
    def shutdown
      unless Unleash.configuration.disable_client
        Unleash.toggle_fetcher.save!
        Unleash.reporter.send unless Unleash.configuration.disable_metrics
        shutdown!
      end
    end

    # quick shutdown: just kill running threads
    def shutdown!
      unless Unleash.configuration.disable_client
        self.fetcher_scheduled_executor.exit
        self.metrics_scheduled_executor.exit unless Unleash.configuration.disable_metrics
      end
    end

    private

    def info
      {
        'appName': Unleash.configuration.app_name,
        'instanceId': Unleash.configuration.instance_id,
        'sdkVersion': "unleash-client-ruby:" + Unleash::VERSION,
        'strategies': Unleash::STRATEGIES.keys,
        'started': Time.now.iso8601(Unleash::TIME_RESOLUTION),
        'interval': Unleash.configuration.metrics_interval_in_millis
      }
    end

    def start_toggle_fetcher
      Unleash.toggle_fetcher = Unleash::ToggleFetcher.new
      self.fetcher_scheduled_executor = Unleash::ScheduledExecutor.new(
        'ToggleFetcher',
        Unleash.configuration.refresh_interval,
        Unleash.configuration.retry_limit
      )
      self.fetcher_scheduled_executor.run do
        Unleash.toggle_fetcher.fetch
      end
    end

    def start_metrics
      Unleash.toggle_metrics = Unleash::Metrics.new
      Unleash.reporter = Unleash::MetricsReporter.new
      self.metrics_scheduled_executor = Unleash::ScheduledExecutor.new(
        'MetricsReporter',
        Unleash.configuration.metrics_interval,
        Unleash.configuration.retry_limit
      )
      self.metrics_scheduled_executor.run do
        Unleash.reporter.send
      end
    end

    def register
      Unleash.logger.debug "register()"

      # Send the request, if possible
      begin
        response = Unleash::Util::Http.post(Unleash.configuration.client_register_url, info.to_json)
      rescue StandardError => e
        Unleash.logger.error "unable to register client with unleash server due to exception #{e.class}:'#{e}'."
        Unleash.logger.error "stacktrace: #{e.backtrace}"
      end
      Unleash.logger.debug "client registered: #{response}"
    end
  end
end