Class: BetterTranslate::Providers::BaseHttpProvider Abstract
- Inherits:
-
Object
- Object
- BetterTranslate::Providers::BaseHttpProvider
- Defined in:
- lib/better_translate/providers/base_http_provider.rb
Overview
Subclasses must implement #translate_text and #translate_batch
Base class for HTTP-based translation providers
Implements common functionality:
- Faraday HTTP client with retry logic
- Exponential backoff with jitter
- Rate limiting
- Caching
- Error handling
Direct Known Subclasses
Instance Attribute Summary collapse
-
#cache ⇒ Cache
readonly
The cache instance.
-
#config ⇒ Configuration
readonly
The configuration object.
-
#rate_limiter ⇒ RateLimiter
readonly
The rate limiter instance.
Instance Method Summary collapse
-
#build_cache_key(text, target_lang_code) ⇒ String
protected
private
Build cache key.
-
#calculate_backoff(attempt) ⇒ Float
protected
private
Calculate exponential backoff with jitter.
-
#handle_response(response) ⇒ void
protected
private
Handle HTTP response.
-
#http_client ⇒ Faraday::Connection
protected
private
Get or create HTTP client.
-
#initialize(config) ⇒ BaseHttpProvider
constructor
Initialize the provider.
-
#log_retry(attempt, delay, error) ⇒ void
protected
private
Log retry attempt.
-
#make_request(method, url, body: nil, headers: {}) ⇒ Faraday::Response
protected
private
Make an HTTP request with retry logic.
-
#translate_batch(texts, target_lang_code, target_lang_name) ⇒ Array<String>
Translate multiple texts in a batch.
-
#translate_text(text, target_lang_code, target_lang_name) ⇒ String
Translate a single text string.
-
#with_cache(cache_key) ⇒ String
protected
private
Get from cache or execute block.
Constructor Details
#initialize(config) ⇒ BaseHttpProvider
Initialize the provider
52 53 54 55 56 |
# File 'lib/better_translate/providers/base_http_provider.rb', line 52 def initialize(config) @config = config @cache = Cache.new(capacity: config.cache_size, ttl: config.cache_ttl) @rate_limiter = RateLimiter.new(delay: 0.5) end |
Instance Attribute Details
#cache ⇒ Cache (readonly)
Returns The cache instance.
39 40 41 |
# File 'lib/better_translate/providers/base_http_provider.rb', line 39 def cache @cache end |
#config ⇒ Configuration (readonly)
Returns The configuration object.
36 37 38 |
# File 'lib/better_translate/providers/base_http_provider.rb', line 36 def config @config end |
#rate_limiter ⇒ RateLimiter (readonly)
Returns The rate limiter instance.
42 43 44 |
# File 'lib/better_translate/providers/base_http_provider.rb', line 42 def rate_limiter @rate_limiter end |
Instance Method Details
#build_cache_key(text, target_lang_code) ⇒ String (protected)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Build cache key
234 235 236 |
# File 'lib/better_translate/providers/base_http_provider.rb', line 234 def build_cache_key(text, target_lang_code) "#{text}:#{target_lang_code}" end |
#calculate_backoff(attempt) ⇒ Float (protected)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Calculate exponential backoff with jitter
172 173 174 175 176 177 178 179 |
# File 'lib/better_translate/providers/base_http_provider.rb', line 172 def calculate_backoff(attempt) base_delay = config.retry_delay max_delay = 60.0 jitter = rand * 0.3 # 0-30% jitter delay = base_delay * (2**(attempt - 1)) * (1 + jitter) [delay, max_delay].min end |
#handle_response(response) ⇒ void (protected)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
This method returns an undefined value.
Handle HTTP response
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 |
# File 'lib/better_translate/providers/base_http_provider.rb', line 139 def handle_response(response) case response.status when 200..299 # Success when 429 raise RateLimitError.new( "Rate limit exceeded", context: { status: response.status, body: response.body } ) when 400..499 raise ApiError.new( "Client error: #{response.status}", context: { status: response.status, body: response.body } ) when 500..599 raise ApiError.new( "Server error: #{response.status}", context: { status: response.status, body: response.body } ) else raise ApiError.new( "Unexpected status: #{response.status}", context: { status: response.status, body: response.body } ) end end |
#http_client ⇒ Faraday::Connection (protected)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Get or create HTTP client
201 202 203 204 205 206 207 |
# File 'lib/better_translate/providers/base_http_provider.rb', line 201 def http_client @http_client ||= Faraday.new do |f| f..timeout = config.request_timeout f..open_timeout = 10 f.adapter Faraday.default_adapter end end |
#log_retry(attempt, delay, error) ⇒ void (protected)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
This method returns an undefined value.
Log retry attempt
189 190 191 192 193 194 |
# File 'lib/better_translate/providers/base_http_provider.rb', line 189 def log_retry(attempt, delay, error) return unless config.verbose puts "[BetterTranslate] Retry #{attempt}/#{config.max_retries} " \ "after #{delay.round(2)}s (#{error.class}: #{error.})" end |
#make_request(method, url, body: nil, headers: {}) ⇒ Faraday::Response (protected)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Make an HTTP request with retry logic
Implements exponential backoff with jitter and rate limiting. Automatically retries on rate limit and API errors.
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 |
# File 'lib/better_translate/providers/base_http_provider.rb', line 105 def make_request(method, url, body: nil, headers: {}) attempt = 0 loop do attempt += 1 begin rate_limiter.wait response = http_client.send(method, url) do |req| req.headers.merge!(headers) req.body = body.to_json if body end rate_limiter.record_request handle_response(response) return response rescue RateLimitError, ApiError => e raise if attempt >= config.max_retries delay = calculate_backoff(attempt) log_retry(attempt, delay, e) sleep(delay) end end end |
#translate_batch(texts, target_lang_code, target_lang_name) ⇒ Array<String>
Translate multiple texts in a batch
86 87 88 |
# File 'lib/better_translate/providers/base_http_provider.rb', line 86 def translate_batch(texts, target_lang_code, target_lang_name) raise NotImplementedError, "#{self.class} must implement #translate_batch" end |
#translate_text(text, target_lang_code, target_lang_name) ⇒ String
Translate a single text string
70 71 72 |
# File 'lib/better_translate/providers/base_http_provider.rb', line 70 def translate_text(text, target_lang_code, target_lang_name) raise NotImplementedError, "#{self.class} must implement #translate_text" end |
#with_cache(cache_key) ⇒ String (protected)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Get from cache or execute block
216 217 218 219 220 221 222 223 224 225 |
# File 'lib/better_translate/providers/base_http_provider.rb', line 216 def with_cache(cache_key) return yield unless config.cache_enabled cached = cache.get(cache_key) return cached if cached result = yield cache.set(cache_key, result) result end |