Class: Ksef::HTTP::Retry
- Inherits:
-
Faraday::Middleware
- Object
- Faraday::Middleware
- Ksef::HTTP::Retry
- Defined in:
- lib/ksef/http/retry.rb
Overview
Re-issues a failed request when RetryPolicy says it is safe to.
Until 2026-08-23 this did not exist: RetryPolicy was constructed, validated,
documented as a constructor option and never consulted, so Retry-After was
honoured nowhere and retry: was silently inert. The policy object was right all
along; nothing called it.
What may be retried, and why so little
Every decision is delegated to RetryPolicy#retryable?, which refuses anything
but GET and HEAD (DESIGN.md §6.7). That rule is a business one, not a technical
one: a duplicate invoice in KSeF is a real tax problem, so a POST whose response
never arrived must surface to the caller, who alone knows whether re-sending is safe.
The per-invoice duplicate status 440 exists precisely because this happens, and it
is not this middleware's job to make it happen more often.
There is exactly one documented exception anywhere in the gem, and it is not here:
Crypto::PublicKeys#with_key_rotation's opt-in 21470 remediation, which a
caller invokes deliberately (docs/REFERENCE.md §10.2).
Placement in the stack is load-bearing
Registered outside ErrorHandler, so it catches the typed exceptions the handler
raises rather than inspecting raw statuses — one place decides what a status means.
Registered inside request :json, so a retry re-sends the already-encoded body
instead of encoding it twice.
The body is restored before each attempt because an adapter may consume it: without that, attempt two sends an empty body and the retry silently changes the request.
Constant Summary collapse
- RETRYABLE =
The four classes ErrorHandler raises that can be worth another attempt: a rate limit, a server fault, and the two transport failures. Everything else — 400, 401, 403, 410 — is a definite answer that retrying cannot improve.
[ Ksef::RateLimitedError, Ksef::ServerError, Ksef::TimeoutError, Ksef::ConnectionError ].freeze
Instance Method Summary collapse
- #call(env) ⇒ Object
-
#initialize(app, policy:, sleeper: nil, logger: nil) ⇒ Retry
constructor
A new instance of Retry.
Constructor Details
#initialize(app, policy:, sleeper: nil, logger: nil) ⇒ Retry
Returns a new instance of Retry.
50 51 52 53 54 55 |
# File 'lib/ksef/http/retry.rb', line 50 def initialize(app, policy:, sleeper: nil, logger: nil) super(app) @policy = policy @sleeper = sleeper || ->(seconds) { sleep(seconds) } @logger = logger end |
Instance Method Details
#call(env) ⇒ Object
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
# File 'lib/ksef/http/retry.rb', line 57 def call(env) body = env.body attempt = 1 begin env.body = body @app.call(env) rescue *RETRYABLE => e raise unless retry?(env, e, attempt) wait = @policy.interval_for(attempt: attempt, retry_after: retry_after(e)) announce(env, e, attempt, wait) @sleeper.call(wait) attempt += 1 retry end end |