barkibu-kb 0.32.0 → 1.1.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: b53777b2236e073a8943960012027f45b5dcb853c068e1f09a2fbf093d863791
4
- data.tar.gz: d02bbd5e466a2c0dd0fe58d6a5221851c76edfdc15887786d26088cf3691c731
3
+ metadata.gz: d6665ca6f0d74295cacf6bea9ee921b3dba5decc6b5cb3775bbaa0392fd65b86
4
+ data.tar.gz: 700cae8005557d25ff41c3f9583725686485eff37ccbb0eec11ff07473ad9077
5
5
  SHA512:
6
- metadata.gz: aae274ead93d952cd495e8f88c6c7a437011e83a5074f2b05c297d3c573a8f2593584e4a3fd30750589eb2d32c186ea112a138a1560b6cd161b41a71e1d90131
7
- data.tar.gz: 06bb84dfd34a396755856ba5e5d17438a40bcc4189b5b6c7e22c69f43daccc431dda6ecbbefa40c4d420615200ef60f7d97a5db0d8948baf6b6425933c2942c0
6
+ metadata.gz: 97dac9ae9946f9398bd62b2fda16acbd978c1e4e153e23884ab78ac3a055dec7d201fcbf3a98ed4b65403324af2b03d034a6073f30d15c20690699021fccae74
7
+ data.tar.gz: f9ed89dff91778420037ad50e7531af48d9b7b6d11c7d92afb1d05cdc31192498310520da51d35aa32e9ed77041e808137f5d9b699fcea24d495f2d17379b475
@@ -0,0 +1,27 @@
1
+ name: CI
2
+
3
+ on:
4
+ pull_request:
5
+ push:
6
+ branches: [master]
7
+
8
+ jobs:
9
+ rubocop:
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - uses: actions/checkout@v5
13
+ - uses: ruby/setup-ruby@v1
14
+ with:
15
+ ruby-version: '3.4'
16
+ bundler-cache: true
17
+ - run: bundle exec rubocop lib spec
18
+
19
+ rspec:
20
+ runs-on: ubuntu-latest
21
+ steps:
22
+ - uses: actions/checkout@v5
23
+ - uses: ruby/setup-ruby@v1
24
+ with:
25
+ ruby-version: '3.4'
26
+ bundler-cache: true
27
+ - run: bundle exec rspec
data/CHANGELOG.md CHANGED
@@ -6,7 +6,18 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
8
  ## [unreleased]
9
- - See diff: https://github.com/barkibu/kb-ruby/compare/v0.32.0...HEAD
9
+ - See diff: https://github.com/barkibu/kb-ruby/compare/v1.1.0...HEAD
10
+
11
+ ## [1.1.0]
12
+ - Add `read_timeout:` to `KB::Client#request` to raise the read budget for a single call (e.g. `GET /v1/pets/birthdays`, whose server-side work runs for seconds). Connect and write budgets stay global; the override does not leak into later calls on the same connection.
13
+
14
+ ## [1.0.0]
15
+ - [Breaking changes] Split the single global request timeout into per-phase budgets: `KB.config.request.connect_timeout` (default 1s, bounds TCP connect + TLS handshake), `write_timeout` (default 3s), `read_timeout` (default 5s). `KB.config.request.timeout` is removed — assigning it now raises `NoMethodError` at boot. Migration: a previous global `timeout` maps to `read_timeout` (e.g. `KB_REQUEST_TIMEOUT_SECONDS=12` → `read_timeout = 12`).
16
+ - [Breaking changes] Switch the HTTP adapter from http.rb (`faraday-http`) to Net::HTTP (`faraday-net_http`) — the stock adapter honours all three phase timeouts, aligns the KB client with the rest of our outbound HTTP, and opens a one-line upgrade path to `faraday-net_http_persistent` for connection reuse. Raw error classes change accordingly (`Net::OpenTimeout`/`Net::ReadTimeout`/`Net::WriteTimeout`/`Errno::*` instead of `HTTP::*`) — relevant to APM span queries on `error.type`.
17
+ - Faraday-level wrapping keeps the same three classes (`Faraday::TimeoutError`/`ConnectionFailed`/`SSLError`) with one movement between them: a connect/TLS-phase expiry now surfaces as `Faraday::ConnectionFailed` (was `Faraday::TimeoutError`), making `ConnectionFailed` cleanly mean "the request never got through the pipe".
18
+ - Net::HTTP's idempotent auto-retry stays disabled (`max_retries = 0`, enforced by the adapter and pinned by a spec) — no behaviour change vs. the previous no-retry client.
19
+ - There is no total request budget anymore; worst-case wall clock is the sum of the phase budgets rather than a single number.
20
+ - barkibu-kb-fake: disable Sinatra's host authorization (`set :host_authorization, permitted_hosts: []`). Sinatra >= 4.1 authorizes the Host header and, when it infers a development environment, only permits localhost-style hosts — rejecting requests to the stubbed KB host with `403 Host not permitted`. Permitting the host on the consumer side stops working with the net_http adapter, because WebMock intercepts before Net::HTTP adds the Host header, so the header is absent and can never match a permitted list. Consumers can drop their own `set :host_authorization` workarounds.
10
21
 
11
22
  ## [0.32.0]
12
23
  - Allow Ruby 3.3/3.4: raise `required_ruby_version` ceiling to `< 3.6` (floor stays `>= 2.6`)
data/Gemfile.lock CHANGED
@@ -1,17 +1,17 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- barkibu-kb (0.32.0)
4
+ barkibu-kb (1.1.0)
5
5
  activemodel (>= 4.0.2)
6
6
  activerecord
7
7
  activesupport (>= 3.0.0)
8
8
  dry-configurable (~> 0.9)
9
9
  faraday
10
- faraday-http
10
+ faraday-net_http (~> 1.0)
11
11
  faraday_middleware
12
12
  i18n
13
- barkibu-kb-fake (0.32.0)
14
- barkibu-kb (= 0.32.0)
13
+ barkibu-kb-fake (1.1.0)
14
+ barkibu-kb (= 1.1.0)
15
15
  countries
16
16
  sinatra
17
17
  webmock
@@ -52,8 +52,6 @@ GEM
52
52
  rexml
53
53
  diff-lcs (1.4.4)
54
54
  docile (1.4.0)
55
- domain_name (0.5.20190701)
56
- unf (>= 0.0.5, < 1.0.0)
57
55
  drb (2.2.3)
58
56
  dry-configurable (0.16.1)
59
57
  dry-core (~> 0.6)
@@ -76,9 +74,6 @@ GEM
76
74
  faraday-em_http (1.0.0)
77
75
  faraday-em_synchrony (1.0.0)
78
76
  faraday-excon (1.1.0)
79
- faraday-http (1.1.0)
80
- faraday (~> 1.0)
81
- http (>= 4.0, < 6)
82
77
  faraday-httpclient (1.0.1)
83
78
  faraday-multipart (1.0.4)
84
79
  multipart-post (~> 2)
@@ -89,25 +84,10 @@ GEM
89
84
  faraday-retry (1.0.3)
90
85
  faraday_middleware (1.2.0)
91
86
  faraday (~> 1.0)
92
- ffi (1.15.5)
93
- ffi-compiler (1.0.1)
94
- ffi (>= 1.0.0)
95
- rake
96
87
  hashdiff (1.0.1)
97
- http (5.1.1)
98
- addressable (~> 2.8)
99
- http-cookie (~> 1.0)
100
- http-form_data (~> 2.2)
101
- llhttp-ffi (~> 0.4.0)
102
- http-cookie (1.0.5)
103
- domain_name (~> 0.5)
104
- http-form_data (2.3.0)
105
88
  i18n (1.15.2)
106
89
  concurrent-ruby (~> 1.0)
107
90
  json (2.20.0)
108
- llhttp-ffi (0.4.0)
109
- ffi-compiler (~> 1.0)
110
- rake (~> 13.0)
111
91
  logger (1.7.0)
112
92
  minitest (6.0.6)
113
93
  drb (~> 2.0)
@@ -174,9 +154,6 @@ GEM
174
154
  tzinfo (2.0.6)
175
155
  concurrent-ruby (~> 1.0)
176
156
  unaccent (0.4.0)
177
- unf (0.1.4)
178
- unf_ext
179
- unf_ext (0.0.8.2)
180
157
  unicode-display_width (2.5.0)
181
158
  uri (1.1.1)
182
159
  webmock (3.14.0)
data/README.md CHANGED
@@ -18,6 +18,15 @@ Or install it yourself as:
18
18
 
19
19
  $ gem install kb
20
20
 
21
+ ## Development
22
+
23
+ Specs and RuboCop run on every pull request (`.github/workflows/ci.yml`) on Ruby 3.4. Locally:
24
+
25
+ ```sh
26
+ docker compose run --rm kb bundle exec rspec
27
+ docker compose run --rm kb bundle exec rubocop lib spec
28
+ ```
29
+
21
30
  ## Usage
22
31
 
23
32
  This gem wraps the Knowledge Base Api and exposes CRUD-_able_ entities into the requiring application.
@@ -43,9 +52,26 @@ KB.config.log_level = :debugger # :info by default
43
52
  ```
44
53
 
45
54
  #### Request timeout configuration
55
+
56
+ Timeouts are per phase, and each phase fails with its own error class:
57
+ `connect_timeout` maps to Net::HTTP's `open_timeout`, bounding TCP connect plus
58
+ the TLS handshake (`Net::OpenTimeout`); `read_timeout` bounds the wait for the
59
+ response (`Net::ReadTimeout`); `write_timeout` bounds sending the request
60
+ (`Net::WriteTimeout`).
61
+
46
62
  ```ruby
47
63
  # config/initializers/kb_ruby.rb
48
- KB.config.request.timeout = 10 # 5 by default
64
+ KB.config.request.connect_timeout = 2 # 1 by default; TCP connect + TLS handshake
65
+ KB.config.request.write_timeout = 4 # 3 by default
66
+ KB.config.request.read_timeout = 10 # 5 by default
67
+ ```
68
+
69
+ The read budget can be raised for a single call through `KB::Client#request`, for
70
+ the few endpoints whose server-side work legitimately runs for seconds. Connect
71
+ and write budgets stay global:
72
+
73
+ ```ruby
74
+ KB::Pet.kb_client.request('birthdays', filters: { month: 9, day: 22, size: 1000 }, read_timeout: 30)
49
75
  ```
50
76
 
51
77
  ### Exposed Entities
data/barkibu-kb.gemspec CHANGED
@@ -51,7 +51,7 @@ Gem::Specification.new do |spec|
51
51
  spec.add_runtime_dependency 'activerecord'
52
52
  spec.add_runtime_dependency 'activesupport', '>= 3.0.0'
53
53
  spec.add_runtime_dependency 'faraday'
54
- spec.add_runtime_dependency 'faraday-http'
54
+ spec.add_runtime_dependency 'faraday-net_http', '~> 1.0'
55
55
  spec.add_runtime_dependency 'faraday_middleware'
56
56
  spec.add_runtime_dependency 'i18n'
57
57
  end
data/lib/barkibu-kb.rb CHANGED
@@ -5,7 +5,6 @@ require 'active_support'
5
5
  require 'active_support/core_ext/array'
6
6
  require 'faraday'
7
7
  require 'faraday_middleware'
8
- require 'faraday/http'
9
8
  require 'dry/configurable'
10
9
 
11
10
  module KB
@@ -19,7 +18,9 @@ module KB
19
18
  setting :log_level, default: :info
20
19
 
21
20
  setting :request do
22
- setting :timeout, default: 5
21
+ setting :connect_timeout, default: 1
22
+ setting :write_timeout, default: 3
23
+ setting :read_timeout, default: 5
23
24
  end
24
25
  end
25
26
 
data/lib/kb/client.rb CHANGED
@@ -7,12 +7,16 @@ module KB
7
7
  @base_url = base_url
8
8
  end
9
9
 
10
- def request(sub_path, filters: nil, method: :get)
11
- return connection.public_send(method, sub_path, attributes_to_json(filters)).body if method != :get
10
+ # `read_timeout` overrides KB.config.request.read_timeout for this one call only,
11
+ # for the few endpoints whose server-side work legitimately runs for seconds
12
+ # (e.g. GET /v1/pets/birthdays). Connect and write budgets stay global.
13
+ def request(sub_path, filters: nil, method: :get, read_timeout: nil)
14
+ options = request_options(read_timeout)
15
+ return connection.public_send(method, sub_path, attributes_to_json(filters), &options).body if method != :get
12
16
 
13
17
  cache_key = "#{@base_url}/#{sub_path}/#{(filters || {}).sort.to_h}"
14
18
  KB::Cache.fetch(cache_key) do
15
- connection.public_send(method, sub_path, filters).body
19
+ connection.public_send(method, sub_path, filters, &options).body
16
20
  end
17
21
  end
18
22
 
@@ -74,9 +78,7 @@ module KB
74
78
  end
75
79
 
76
80
  def connection
77
- @connection ||= Faraday.new(url: base_url,
78
- headers: headers,
79
- request: { timeout: KB.config.request.timeout }) do |conn|
81
+ @connection ||= Faraday.new(url: base_url, headers: headers, request: request_timeouts) do |conn|
80
82
  conn.response :json
81
83
  conn.response :raise_error
82
84
  if KB.config.log_level == :debugger
@@ -84,8 +86,22 @@ module KB
84
86
  logger.filter(/(X-api-key:\s)("\w+")/, '\1[API_KEY_SCRUBBED]')
85
87
  end
86
88
  end
87
- conn.adapter :http
89
+ conn.adapter :net_http
88
90
  end
89
91
  end
92
+
93
+ def request_options(read_timeout)
94
+ return nil if read_timeout.nil?
95
+
96
+ ->(req) { req.options.read_timeout = read_timeout }
97
+ end
98
+
99
+ def request_timeouts
100
+ {
101
+ open_timeout: KB.config.request.connect_timeout,
102
+ write_timeout: KB.config.request.write_timeout,
103
+ read_timeout: KB.config.request.read_timeout
104
+ }
105
+ end
90
106
  end
91
107
  end
data/lib/kb/fake/api.rb CHANGED
@@ -44,6 +44,16 @@ module KB
44
44
  include BoundedContext::PetFamily::PetContracts
45
45
  include BoundedContext::PetFamily::Products
46
46
 
47
+ # Sinatra >= 4.1 ships Rack::Protection::HostAuthorization, which authorizes
48
+ # on the Host header and, when it infers a development environment, only
49
+ # permits localhost-style hosts — rejecting requests addressed to the
50
+ # stubbed KB host with "403 Host not permitted". Permitting specific hosts
51
+ # on the consumer side is no fix either: with the net_http adapter WebMock
52
+ # intercepts before Net::HTTP adds the Host header, so the header is absent
53
+ # and can never match a permitted list. An empty list disables the check;
54
+ # it guards against DNS rebinding, which cannot apply to an in-process fake.
55
+ set :host_authorization, permitted_hosts: []
56
+
47
57
  set :state, ApiState.new
48
58
 
49
59
  def self.snapshot
data/lib/kb/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module KB
2
- VERSION = '0.32.0'.freeze
2
+ VERSION = '1.1.0'.freeze
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: barkibu-kb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.32.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Léo Figea
@@ -220,19 +220,19 @@ dependencies:
220
220
  - !ruby/object:Gem::Version
221
221
  version: '0'
222
222
  - !ruby/object:Gem::Dependency
223
- name: faraday-http
223
+ name: faraday-net_http
224
224
  requirement: !ruby/object:Gem::Requirement
225
225
  requirements:
226
- - - ">="
226
+ - - "~>"
227
227
  - !ruby/object:Gem::Version
228
- version: '0'
228
+ version: '1.0'
229
229
  type: :runtime
230
230
  prerelease: false
231
231
  version_requirements: !ruby/object:Gem::Requirement
232
232
  requirements:
233
- - - ">="
233
+ - - "~>"
234
234
  - !ruby/object:Gem::Version
235
- version: '0'
235
+ version: '1.0'
236
236
  - !ruby/object:Gem::Dependency
237
237
  name: faraday_middleware
238
238
  requirement: !ruby/object:Gem::Requirement
@@ -271,6 +271,7 @@ extra_rdoc_files: []
271
271
  files:
272
272
  - ".env.example"
273
273
  - ".github/pull_request_template.md"
274
+ - ".github/workflows/ci.yml"
274
275
  - ".github/workflows/release.yaml"
275
276
  - ".gitignore"
276
277
  - ".rspec"