amplitude-experiment 1.0.0.beta.1 → 1.0.0.beta.4

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: f67be77264977612b2728ee49db7923a26414cdeefc71d15059cbcd6564031ac
4
- data.tar.gz: d59583f45788bea92e6c5855b0cb2f754a87a2b022784f6a3e89eca239173819
3
+ metadata.gz: 653e4953eeea7497bb43f1e76c144c8fe7360dcc53c7aa3f9c63e3b28e1052ee
4
+ data.tar.gz: 9b8ea31ccb93aebd815019f6dab4f739ea49b96177800dc6a39b9f1907f64ad0
5
5
  SHA512:
6
- metadata.gz: fd383c6a79f4164fbc3897d12256da8c19b5824be542faa23b43384ad32aa781c6cfee5b4101d015cd6fbef5994818ddc8ddd77addd83f8522c9716063f1dd45
7
- data.tar.gz: b0d7f6429e872a86027cd0f34b2e796b04be39cc672616e5e99e543b32635dbe8226c06356f941fcfd7e118d608a4d151ce80fa6b6be10cfa5e41ae08e656138
6
+ metadata.gz: 4a1b221d66a28d1cc53c20c5eba088baa3a180ec628603d8801ed759ef893b6a74162abb8396ed3bac2f97f51aa45e7536adedc4509f1d719c2495ff2e129df1
7
+ data.tar.gz: 1757f94f26bf55016c8604ee065ae4d24d95b431ac7a27687190fe8e138d6ac402d94248eba90f9c23d94fd918179d28da8ffc02c9c03004e5bdeaafa8e24db1
data/README.md CHANGED
@@ -5,8 +5,10 @@
5
5
  <br />
6
6
  </p>
7
7
 
8
- # experiment-ruby-server
9
- Ruby Server SDK for Experiment
8
+ [![Gem Version](https://badge.fury.io/rb/amplitude-experiment.svg)](https://badge.fury.io/rb/amplitude-experiment)
9
+
10
+ # Experiment Ruby SDK
11
+ Amplitude Ruby Server SDK for Experiment.
10
12
 
11
13
  ## Installation
12
14
  Into Gemfile from rubygems.org:
@@ -17,6 +19,11 @@ Into environment gems from rubygems.org:
17
19
  ```ruby
18
20
  gem install 'amplitude-experiment'
19
21
  ```
22
+ To install beta versions:
23
+ ```ruby
24
+ gem install amplitude-experiment --pre
25
+ ```
26
+
20
27
 
21
28
  ## Quick Start
22
29
  ```ruby
@@ -57,5 +64,10 @@ unless variant.nil?
57
64
  end
58
65
  ```
59
66
 
67
+ ## More Information
68
+ Please visit our :100:[Developer Center](https://www.docs.developers.amplitude.com/experiment/sdks/ruby-sdk/) for more instructions on using our the SDK.
69
+
70
+ See our [Experiment Ruby SDK Docs](https://amplitude.github.io/experiment-ruby-server/) for a list and description of all available SDK methods.
71
+
60
72
  ## Need Help?
61
73
  If you have any problems or issues over our SDK, feel free to [create a github issue](https://github.com/amplitude/experiments-ruby-server/issues/new) or submit a request on [Amplitude Help](https://help.amplitude.com/hc/en-us/requests/new).
@@ -19,6 +19,8 @@ module Experiment
19
19
  else
20
20
  Logger::INFO
21
21
  end
22
+ endpoint = "#{@config.server_url}/sdk/vardata"
23
+ @uri = URI(endpoint)
22
24
  raise ArgumentError, 'Experiment API key is empty' if @api_key.nil? || @api_key.empty?
23
25
  end
24
26
 
@@ -91,16 +93,13 @@ module Experiment
91
93
  def do_fetch(user, timeout_millis)
92
94
  start_time = Time.now
93
95
  user_context = add_context(user)
94
- endpoint = "#{@config.server_url}/sdk/vardata"
95
96
  headers = {
96
97
  'Authorization' => "Api-Key #{@api_key}",
97
98
  'Content-Type' => 'application/json;charset=utf-8'
98
99
  }
99
- uri = URI(endpoint)
100
- http = Net::HTTP.new(uri.host, uri.port)
101
- http.use_ssl = true
102
- http.read_timeout = timeout_millis / 1000 if (timeout_millis / 1000) > 0
103
- request = Net::HTTP::Post.new(uri, headers)
100
+ read_timeout = timeout_millis / 1000 if (timeout_millis / 1000) > 0
101
+ http = PersistentHttpClient.get(@uri, { read_timeout: read_timeout })
102
+ request = Net::HTTP::Post.new(@uri, headers)
104
103
  request.body = user_context.to_json
105
104
  if request.body.length > 8000
106
105
  @logger.warn("[Experiment] encoded user object length #{request.body.length} cannot be cached by CDN; must be < 8KB")
@@ -130,7 +129,7 @@ module Experiment
130
129
  # value was previously under the "key" field
131
130
  variant_value = value.fetch('key')
132
131
  end
133
- variants.store(key, Variant.new(variant_value, value.fetch('payload')))
132
+ variants.store(key, Variant.new(variant_value, value.fetch('payload', nil)))
134
133
  end
135
134
  variants
136
135
  end
@@ -0,0 +1,127 @@
1
+ module Experiment
2
+ # Persist Http Client to reuse connection and reduce IO
3
+ class PersistentHttpClient
4
+ DEFAULT_OPTIONS = { read_timeout: 80 }.freeze
5
+
6
+ class << self
7
+ # url: URI / String
8
+ # options: any options that Net::HTTP.new accepts
9
+ def get(url, options = {})
10
+ uri = url.is_a?(URI) ? url : URI(url)
11
+ connection_manager.get_client(uri, options)
12
+ end
13
+
14
+ private
15
+
16
+ # each thread gets its own connection manager
17
+ def connection_manager
18
+ # before getting a connection manager
19
+ # we first clear all old ones
20
+ remove_old_managers
21
+ Thread.current[:http_connection_manager] ||= new_manager
22
+ end
23
+
24
+ def new_manager
25
+ # create a new connection manager in a thread safe way
26
+ mutex.synchronize do
27
+ manager = ConnectionManager.new
28
+ connection_managers << manager
29
+ manager
30
+ end
31
+ end
32
+
33
+ def remove_old_managers
34
+ mutex.synchronize do
35
+ removed = connection_managers.reject!(&:stale?)
36
+ (removed || []).each(&:close_connections!)
37
+ end
38
+ end
39
+
40
+ # mutex isn't needed for CRuby, but might be needed
41
+ # for other Ruby implementations
42
+ def mutex
43
+ @mutex ||= Mutex.new
44
+ end
45
+
46
+ def connection_managers
47
+ @connection_managers ||= []
48
+ end
49
+ end
50
+
51
+ # connection manager represents
52
+ # a cache of all keep-alive connections
53
+ # in a current thread
54
+ class ConnectionManager
55
+ # if a client wasn't used within this time range
56
+ # it gets removed from the cache and the connection closed.
57
+ # This helps to make sure there are no memory leaks.
58
+ STALE_AFTER = 300 # 5 minutes
59
+
60
+ # Seconds to reuse the connection of the previous request. If the idle time is less than this Keep-Alive Timeout,
61
+ # Net::HTTP reuses the TCP/IP socket used by the previous communication. Source: Ruby docs
62
+ KEEP_ALIVE_TIMEOUT = 30 # seconds
63
+
64
+ # KEEP_ALIVE_TIMEOUT vs STALE_AFTER
65
+ # STALE_AFTER - how long an Net::HTTP client object is cached in ruby
66
+ # KEEP_ALIVE_TIMEOUT - how long that client keeps TCP/IP socket open.
67
+
68
+ attr_accessor :clients_store, :last_used
69
+
70
+ def initialize
71
+ self.clients_store = {}
72
+ self.last_used = Time.now
73
+ end
74
+
75
+ def get_client(uri, options)
76
+ mutex.synchronize do
77
+ # refresh the last time a client was used,
78
+ # this prevents the client from becoming stale
79
+ self.last_used = Time.now
80
+
81
+ # we use params as a cache key for clients.
82
+ # 2 connections to the same host but with different
83
+ # options are going to use different HTTP clients
84
+ params = [uri.host, uri.port, options]
85
+ client = clients_store[params]
86
+
87
+ return client if client
88
+
89
+ client = Net::HTTP.new(uri.host, uri.port)
90
+ client.keep_alive_timeout = KEEP_ALIVE_TIMEOUT
91
+
92
+ # set SSL to true if a scheme is https
93
+ client.use_ssl = uri.scheme == 'https'
94
+
95
+ # dynamically set Net::HTTP options
96
+ DEFAULT_OPTIONS.merge(options).each_pair do |key, value|
97
+ client.public_send("#{key}=", value)
98
+ end
99
+
100
+ # open connection
101
+ client.start
102
+
103
+ # cache the client
104
+ clients_store[params] = client
105
+
106
+ client
107
+ end
108
+ end
109
+
110
+ # close connections for each client
111
+ def close_connections!
112
+ mutex.synchronize do
113
+ clients_store.values.each(&:finish)
114
+ self.clients_store = {}
115
+ end
116
+ end
117
+
118
+ def stale?
119
+ Time.now - last_used > STALE_AFTER
120
+ end
121
+
122
+ def mutex
123
+ @mutex ||= Mutex.new
124
+ end
125
+ end
126
+ end
127
+ end
@@ -1,3 +1,3 @@
1
1
  module Experiment
2
- VERSION = '1.0.0.beta.1'.freeze
2
+ VERSION = '1.0.0.beta.4'.freeze
3
3
  end
data/lib/experiment.rb CHANGED
@@ -1,8 +1,10 @@
1
+ require 'experiment/version'
1
2
  require 'experiment/config'
2
3
  require 'experiment/cookie'
3
4
  require 'experiment/user'
4
5
  require 'experiment/variant'
5
6
  require 'experiment/factory'
7
+ require 'experiment/persistent_http_client'
6
8
  require 'experiment/client'
7
9
 
8
10
  # Amplitude Experiment Module
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: amplitude-experiment
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.beta.1
4
+ version: 1.0.0.beta.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Amplitude
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-04-28 00:00:00.000000000 Z
11
+ date: 2022-06-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -124,6 +124,7 @@ files:
124
124
  - lib/experiment/config.rb
125
125
  - lib/experiment/cookie.rb
126
126
  - lib/experiment/factory.rb
127
+ - lib/experiment/persistent_http_client.rb
127
128
  - lib/experiment/user.rb
128
129
  - lib/experiment/variant.rb
129
130
  - lib/experiment/version.rb