antbird 1.0.0 → 1.2.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: 472e058c1be7a6fdadf9949dc8c73c644ba5c82f3eea3b76fc502623fac4bea8
4
- data.tar.gz: 35d0eff4b83b58a11f9299fca6210922f3243b3c166d7cc20385492bebf80570
3
+ metadata.gz: 4fa1a5ef17ca8b183c23e877b88386b4b28bdf9da8cfc35faf1285be1adb8a13
4
+ data.tar.gz: b7084f2d7fd314254d20f6f382f6947b456efde369ec444ec7621f68ae567920
5
5
  SHA512:
6
- metadata.gz: 569096a452fa059ee7527a8fc48a372fc0c7aa1c6001f467b0ce355240656ac787ae6a4ecdc7065d54d1c3daeecc31bbdc812304e023b5fafe32a0669b770838
7
- data.tar.gz: d0c653d432e0ea31f1e98cc56b5486f126d1697483efae7a4f66f31e0b73669d2a5387be8d41b19e8a9759374df635791d88e3814c16d149001ac0b380c7de28
6
+ metadata.gz: e552dc0dfa4fdfa137a157de7f6b110047542c9c1e79ad881e9b7aeeb48a463e9021ce209b9dac868357aeab16bb2d5f58f37e0644f5faf402852c93a9314a5f
7
+ data.tar.gz: dbac1bc2360ab6120349d8a003d75929142fce2a286f65623b3e9dd75e9699d13e7c113c4394035b7b0d33e88cb7ecb1b7eb6d772c98462f36be527199f653bf
@@ -13,6 +13,9 @@ jobs:
13
13
  matrix:
14
14
  # https://github.com/opensearch-project/OpenSearch/releases
15
15
  search_versions:
16
+ - 3.8.0
17
+ - 3.7.0
18
+ - 3.6.0
16
19
  - 3.5.0
17
20
  - 3.4.0
18
21
  - 3.3.2
@@ -36,7 +39,7 @@ jobs:
36
39
  sudo sysctl -w vm.swappiness=1
37
40
  sudo sysctl -w fs.file-max=262144
38
41
  sudo sysctl -w vm.max_map_count=262144
39
- - uses: actions/checkout@v6
42
+ - uses: actions/checkout@v7
40
43
  - uses: ruby/setup-ruby@v1
41
44
  with:
42
45
  ruby-version: "4.0"
data/Gemfile.lock CHANGED
@@ -1,28 +1,28 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- antbird (1.0.0)
4
+ antbird (1.2.0)
5
5
  faraday (>= 2.0.1)
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
9
9
  specs:
10
- addressable (2.8.9)
10
+ addressable (2.9.0)
11
11
  public_suffix (>= 2.0.2, < 8.0)
12
12
  connection_pool (3.0.2)
13
13
  diff-lcs (1.6.2)
14
- faraday (2.14.1)
14
+ faraday (2.14.3)
15
15
  faraday-net_http (>= 2.0, < 3.5)
16
16
  json
17
17
  logger
18
- faraday-net_http (3.4.2)
18
+ faraday-net_http (3.4.4)
19
19
  net-http (~> 0.5)
20
20
  faraday-net_http_persistent (2.3.1)
21
21
  faraday (~> 2.5)
22
22
  net-http-persistent (>= 4.0.4, < 5)
23
23
  faraday-retry (2.4.0)
24
24
  faraday (~> 2.0)
25
- json (2.19.2)
25
+ json (3.0.1)
26
26
  logger (1.7.0)
27
27
  net-http (0.9.1)
28
28
  uri (>= 0.11.1)
data/README.md CHANGED
@@ -99,6 +99,67 @@ client.bulk(body: [
99
99
  ])
100
100
  ```
101
101
 
102
+ ### Timeouts
103
+
104
+ Default connection timeouts are configured when the client is created:
105
+
106
+ ```ruby
107
+ client = Antbird::Client.new(
108
+ read_timeout: 5, # seconds (default)
109
+ open_timeout: 2, # seconds (default)
110
+ write_timeout: 30, # seconds (default: nil => falls back to read_timeout)
111
+ )
112
+ ```
113
+
114
+ `write_timeout` is optional. When omitted it is left unset and the adapter
115
+ falls back to `read_timeout` for the write phase, preserving existing behavior.
116
+
117
+ Timeouts can be overridden per operation. There are two ways to do it:
118
+
119
+ 1. `http_timeout` — a shorthand that sets the `read`, `open` and `write`
120
+ timeouts all at once for that single request:
121
+
122
+ ```ruby
123
+ # This request alone uses a 60s timeout for read/open/write.
124
+ client.search(body: { query: { match_all: {} } }, http_timeout: 60)
125
+
126
+ # Long-running reindex; give it more time without affecting other calls.
127
+ client.reindex(body: { source: { index: 'a' }, dest: { index: 'b' } }, http_timeout: 600)
128
+ ```
129
+
130
+ 2. `read_timeout` / `open_timeout` / `write_timeout` — override individual
131
+ phases. These may be combined with each other:
132
+
133
+ ```ruby
134
+ client.bulk(body: [{ index: { _id: '1' } }, { field1: 'a' }], open_timeout: 3, write_timeout: 30)
135
+ ```
136
+
137
+ When none of these is given, the client falls back to the values configured at
138
+ initialization time.
139
+
140
+ `http_timeout` is mutually exclusive with `read_timeout` / `open_timeout` /
141
+ `write_timeout`. Passing `http_timeout` together with any of them raises an
142
+ `ArgumentError`:
143
+
144
+ ```ruby
145
+ client.search(body: { query: { match_all: {} } }, http_timeout: 60, open_timeout: 3) # => ArgumentError
146
+ ```
147
+
148
+ All of the above are client-side (HTTP) timeouts and do not collide with the
149
+ server-side `timeout` query parameter that some OpenSearch APIs accept — both
150
+ can be passed together:
151
+
152
+ ```ruby
153
+ client.bulk(
154
+ body: [{ index: { _id: '1' } }, { field1: 'a' }],
155
+ timeout: '30s', # OpenSearch server-side timeout (query parameter)
156
+ http_timeout: 60, # HTTP read/open/write timeout (Faraday)
157
+ )
158
+ ```
159
+
160
+ > `read_timeout` sets Faraday's global `:timeout` (preserving its original
161
+ > behavior), while `open_timeout` / `write_timeout` set those specific phases.
162
+
102
163
  ## Development
103
164
 
104
165
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -0,0 +1,20 @@
1
+ require 'json'
2
+
3
+ module Antbird
4
+ class Client
5
+ # Faraday's JSON response middleware hands parser options to the decoder as
6
+ # a positional Hash (`decoder.parse(body, options)`). json 3.0 turned
7
+ # JSON.parse into `parse(source, **options)`, so that call raises
8
+ # ArgumentError and every response fails with Faraday::ParsingError.
9
+ # Decoding through here keeps antbird working on both json 2.x and 3.x.
10
+ module JsonDecoder
11
+ module_function
12
+
13
+ def parse(body, options = {})
14
+ return ::JSON.parse(body) if options.nil? || options.empty?
15
+
16
+ ::JSON.parse(body, **options)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -1,5 +1,6 @@
1
1
  require 'faraday'
2
2
  require 'antbird/client/errors'
3
+ require 'antbird/client/json_decoder'
3
4
 
4
5
  module Antbird
5
6
  class Client
@@ -9,14 +10,16 @@ module Antbird
9
10
  version: nil,
10
11
  read_timeout: 5,
11
12
  open_timeout: 2,
13
+ write_timeout: nil,
12
14
  adapter: ::Faraday.default_adapter,
13
15
  &block)
14
16
 
15
- @read_timeout = read_timeout
16
- @open_timeout = open_timeout
17
- @adapter = adapter
18
- @block = block
19
- @url = url
17
+ @read_timeout = read_timeout
18
+ @open_timeout = open_timeout
19
+ @write_timeout = write_timeout
20
+ @adapter = adapter
21
+ @block = block
22
+ @url = url
20
23
 
21
24
  @scope = scope.transform_keys(&:to_sym)
22
25
 
@@ -25,7 +28,7 @@ module Antbird
25
28
  @api_specs = {}
26
29
  end
27
30
  attr_reader :scope, :url
28
- attr_reader :read_timeout, :open_timeout, :adapter
31
+ attr_reader :read_timeout, :open_timeout, :write_timeout, :adapter
29
32
  attr_reader :api_specs, :last_request
30
33
 
31
34
  def scoped(new_scope = {})
@@ -35,6 +38,7 @@ module Antbird
35
38
  version: version,
36
39
  read_timeout: read_timeout,
37
40
  open_timeout: open_timeout,
41
+ write_timeout: write_timeout,
38
42
  adapter: adapter,
39
43
  &@block
40
44
  )
@@ -84,7 +88,7 @@ module Antbird
84
88
  methods.first
85
89
  end
86
90
 
87
- read_timeout = params.delete(:read_timeout)
91
+ timeout_options = extract_timeout_options(params)
88
92
  params.reject! { |_, v| v.nil? }
89
93
 
90
94
  @last_request = {
@@ -100,29 +104,29 @@ module Antbird
100
104
  when :head
101
105
  connection.head(api_path) do |req|
102
106
  req.params = params unless params.empty?
103
- req.options[:timeout] = read_timeout if read_timeout
107
+ apply_timeouts(req, timeout_options)
104
108
  end
105
109
  when :get
106
110
  connection.get(api_path) do |req|
107
111
  req.params = params unless params.empty?
108
112
  req.body = body if body
109
- req.options[:timeout] = read_timeout if read_timeout
113
+ apply_timeouts(req, timeout_options)
110
114
  end
111
115
  when :put
112
116
  connection.put(api_path, body) do |req|
113
117
  req.params = params unless params.empty?
114
- req.options[:timeout] = read_timeout if read_timeout
118
+ apply_timeouts(req, timeout_options)
115
119
  end
116
120
  when :post
117
121
  connection.post(api_path, body) do |req|
118
122
  req.params = params unless params.empty?
119
- req.options[:timeout] = read_timeout if read_timeout
123
+ apply_timeouts(req, timeout_options)
120
124
  end
121
125
  when :delete
122
126
  connection.delete(api_path) do |req|
123
127
  req.params = params unless params.empty?
124
128
  req.body = body if body
125
- req.options[:timeout] = read_timeout if read_timeout
129
+ apply_timeouts(req, timeout_options)
126
130
  end
127
131
  else
128
132
  raise ArgumentError, "Unknown HTTP request method: #{method.inspect}"
@@ -183,10 +187,11 @@ module Antbird
183
187
  @block&.call(conn)
184
188
 
185
189
  conn.request :json
186
- conn.response :json, content_type: /\bjson$/
190
+ conn.response :json, content_type: /\bjson$/, parser_options: { decoder: [JsonDecoder, :parse] }
187
191
 
188
- conn.options[:timeout] = read_timeout
189
- conn.options[:open_timeout] = open_timeout
192
+ conn.options[:timeout] = read_timeout
193
+ conn.options[:open_timeout] = open_timeout
194
+ conn.options[:write_timeout] = write_timeout if write_timeout
190
195
 
191
196
  conn.adapter adapter
192
197
  end
@@ -201,6 +206,44 @@ module Antbird
201
206
 
202
207
  private
203
208
 
209
+ # Builds the per-operation Faraday timeout options from the request params.
210
+ # - http_timeout: overrides read/open/write timeouts all at once. It is
211
+ # mutually exclusive with read_timeout/open_timeout/write_timeout.
212
+ # - read_timeout: legacy per-operation override (sets Faraday's :timeout).
213
+ # - open_timeout / write_timeout: per-operation overrides for those phases.
214
+ # The granular options may be combined with each other.
215
+ # When none is given, the connection-level defaults are used.
216
+ #
217
+ # The read phase is set via Faraday's :timeout key (consistent with the
218
+ # legacy read_timeout path and the connection-level default); :open_timeout
219
+ # and :write_timeout are set explicitly so http_timeout overrides them even
220
+ # when the connection configures its own defaults.
221
+ def extract_timeout_options(params)
222
+ http_timeout = params.delete(:http_timeout)
223
+ read_timeout = params.delete(:read_timeout)
224
+ open_timeout = params.delete(:open_timeout)
225
+ write_timeout = params.delete(:write_timeout)
226
+
227
+ if http_timeout && (read_timeout || open_timeout || write_timeout)
228
+ raise ArgumentError,
229
+ ":http_timeout cannot be combined with :read_timeout, :open_timeout or :write_timeout"
230
+ end
231
+
232
+ if http_timeout
233
+ return { timeout: http_timeout, open_timeout: http_timeout, write_timeout: http_timeout }
234
+ end
235
+
236
+ options = {}
237
+ options[:timeout] = read_timeout if read_timeout
238
+ options[:open_timeout] = open_timeout if open_timeout
239
+ options[:write_timeout] = write_timeout if write_timeout
240
+ options
241
+ end
242
+
243
+ def apply_timeouts(req, timeout_options)
244
+ timeout_options.each { |key, value| req.options[key] = value }
245
+ end
246
+
204
247
  # NOTE: stable sort
205
248
  def sort_url_paths(url_paths)
206
249
  i = 0
@@ -221,7 +264,7 @@ module Antbird
221
264
  end
222
265
  end
223
266
 
224
- SPECIAL_PARAMS = %i[body method read_timeout].freeze
267
+ SPECIAL_PARAMS = %i[body method http_timeout read_timeout open_timeout write_timeout].freeze
225
268
 
226
269
  def validate_params(api_spec, params, path_params)
227
270
  if api_spec.dig('body', 'required') && !params.key?(:body)