cswork / libraryOpen practice workspace

Articles

Spring Cloud OpenFeign Interview Questions: Timeouts, Retries, and Client Configuration

Practice Spring Cloud OpenFeign interview questions with timeout budgets, retry defaults, client configuration traces, and safe lost-response recovery.

A Spring Cloud OpenFeign client times out while creating a refund. The server may have committed the refund before the response was lost. Turning on retries can improve availability and create duplicate side effects at the same time. The useful interview answer starts with the effective client configuration and ends with a request lifecycle that remains safe when the outcome is uncertain.

This guide uses original configuration and failure exercises. Official facts are linked to Spring Cloud OpenFeign 5.0.3 documentation, the version displayed when checked on September 30, 2026, and upstream Feign sources. Design inference is labeled separately. There are no candidate reports or employer-specific interview claims. Use the Spring Cloud release train and transport actually deployed in your project; configuration names and behavior need version context.

For related practice, start with Debug an Async Payment Refund Function with Retries, Then Make It Idempotent. It forces you to separate a transient failure from permission to repeat a business operation.

Does Spring Cloud OpenFeign retry by default?

Official fact: Spring Cloud OpenFeign supplies Retryer.NEVER_RETRY by default. The feature documentation explicitly contrasts that choice with upstream Feign's default retry behavior for relevant I/O and retryable exceptions.

That is the first distinction to make when someone asks “Does Feign retry?” Name the integration. A statement about a plain upstream Feign.builder() is not automatically true of a Spring-managed @FeignClient.

Original exercise: a client method throws an exception once and the test observes one server request. A developer says retries are broken. What must you inspect before accepting that conclusion? Check the effective Retryer, the exception class, the ErrorDecoder, and whether a surrounding layer performs retries independently. A retry policy can only retry the failures it is configured to recognize.

The upstream Feign project explains retryer customization and error decoding. Keep status classification separate from attempt policy: an error decoder maps an HTTP response into an exception; a retryer decides whether and when a retryable exception permits another attempt.

Design inference: a server error code does not establish business safety. A server can commit and then return an error during response construction. A transport exception can occur before the request reaches the server or after the operation has succeeded. Both classification and idempotency matter.

Ask about retries outside Feign as well. A service method, load-balancer integration, gateway, job runner, or caller may repeat the operation. If one layer permits three attempts and another repeats the whole call three times, an original request can produce up to nine downstream attempts under those stated policies. This arithmetic is a design exercise, not a claim about default Spring behavior.

What do connect and read timeouts cover?

A connection timeout and a read timeout constrain different phases. Their exact interaction with connection reuse, DNS, TLS, and pool acquisition depends on the selected HTTP transport and its configuration. Do not describe two property values as a universal end-to-end deadline.

Spring's configuration-property appendix lists integration and transport settings. The Apache HttpClient RequestConfig API distinguishes requesting a pooled connection from waiting for a response. Use those distinctions when that is the transport in the application.

Original measured timeline: a caller has a one-second business deadline. Attempt one waits 80 milliseconds for a pooled connection, spends 120 milliseconds establishing a connection, and waits 650 milliseconds before a read failure. A 100-millisecond backoff takes elapsed time to 950 milliseconds. Starting another full attempt with the original phase limits does not respect the remaining 50 milliseconds.

Design recommendation: carry an overall deadline and avoid launching work that cannot fit the remaining budget. Adjust the supported phase limits or decline another attempt. Include backoff and queueing in the budget. A timeout around a blocking call may stop the caller from waiting without actually interrupting the underlying request, so verify cancellation behavior instead of assuming it.

Do not calculate an absolute worst-case latency merely by adding configured timeouts. Connection reuse can skip phases; retries can repeat phases; transport interpretation can differ. A useful estimate states assumptions and is validated against a controlled slow-server fixture with observed timestamps.

The interviewer may ask why increasing the read timeout made the outage worse. Inference: requests can occupy threads or pooled connections longer, reducing available capacity and increasing queueing. Whether that occurred requires measurements: leased connections, acquisition waits, outstanding requests, and caller deadlines. A larger timeout is a policy change, not an automatic resilience improvement.

Which client configuration wins?

Consider an original application with this named-client configuration:

spring:
  cloud:
    openfeign:
      client:
        config:
          billing:
            connectTimeout: 250
            readTimeout: 750

A Java configuration also supplies request options using longer values. Which settings should you expect? Official fact: configuration properties override configuration bean values by default; spring.cloud.openfeign.client.default-to-properties=false changes that precedence. The Spring feature guide documents this choice.

Do not stop at “YAML wins.” Trace the client name or context identifier, default versus named settings, active profiles, property-source overrides, and the selected transport. An environment variable or remote property source can make the deployed values differ from the repository's example. The interview skill is resolving effective behavior, not reciting a file format.

Question to resolveEvidence to collectMistake it prevents
Which client is this?Name, context identifier, target URLReading another client's settings
Which policy is active?Effective Retryer and decoderAssuming upstream defaults
Which options are applied?Named properties, configuration beans, precedence flagTrusting an unused bean
Which transport runs?Selected client implementation and poolApplying another library's timeout semantics
Which surrounding layer retries?Gateway and service-level attempt tracesHidden attempt multiplication

Official fact: contextId can distinguish separate client configurations for clients that share a service name. A configuration class intended for one client can also affect other clients if it is accidentally included in the application's component scan. These details are covered in the Spring feature documentation.

Design recommendation: put client-specific configuration outside broad scanning or explicitly exclude it as appropriate. Test two clients together: if you only start one, a leaked retryer or interceptor may appear correct. Avoid logging secrets while proving which interceptor is active; use a non-sensitive marker in a test environment.

How do you retry a committed request safely?

Use an original refund trace. At 0 milliseconds the caller sends refund command R with idempotency key K. At 300 milliseconds the server commits R and stores its result. The response disappears. At 750 milliseconds the caller times out. A retry sends the same command and the same key K.

The server must recognize K and return the committed result without creating a second refund. This requires a durable record and an atomic relationship between that record and the side effect. An in-memory map inside the HTTP client cannot supply the server's guarantee.

The key's lifetime follows the business operation, not the individual HTTP attempt. Generating a new UUID in an interceptor for every attempt defeats the purpose. Reusing one key for unrelated refunds is also wrong. Include a request fingerprint so a repeated key with a different amount or target is rejected rather than quietly returning an unrelated result.

Concurrent retries are part of the exercise. Two callers can send K before either sees a response. The server needs a uniqueness constraint, atomic claim, or equivalent coordination so both do not perform the side effect. Define the behavior while the first attempt is still running: wait, return an in-progress response, or provide a status lookup.

Expiration cannot be an incidental cache setting. If the server forgets K before the supported retry horizon ends, an old retry may become a new operation. Document the allowed window and how expired operations are handled. Your Feign retry policy should remain within that contract.

For operations without safe repetition, return an uncertain outcome and reconcile through a status endpoint or durable operation identifier. Do not hide uncertainty behind a fallback that says “success” or silently starts a replacement operation. A fallback should preserve business meaning even when it provides a degraded response.

What should an ErrorDecoder do with 429 and 503?

Separate response interpretation from admission to retry. A 429 may carry a server-requested delay; a 503 may indicate temporary unavailability. Neither means every request can be repeated safely or indefinitely. Parse the supported response information, classify the failure, then apply the operation's attempt and deadline policy.

Design recommendation: bound both attempts and total elapsed time, use appropriate backoff, and add jitter where synchronized retries would overload a shared dependency. A long retry queue can consume the same capacity needed for fresh work. Decide whether the caller should fail quickly, defer to a job queue, or seek operation status.

A decoder test should verify the exception it produces, including relevant delay or diagnostic fields. A retryer test should verify the resulting attempt count. An integrated client test should verify the actual requests sent to a controlled server. These are different proofs; a unit test of one cannot establish all three.

Handle permanent validation failures separately. Retrying a malformed request with unchanged input usually repeats the same failure. Likewise, an authentication problem needs credential or access recovery rather than unbounded transport retries. Describe the supported classification instead of declaring all non-2xx responses transient.

Which tests make the configuration reviewable?

Start the real Spring client with the application's selected HTTP transport against a local stub server. Verify effective named-client timeouts and the default no-retry behavior. Then install the intended retry policy and test one recoverable failure followed by success, a permanent error, and repeated failure until the budget is exhausted.

Add the committed-but-response-lost case. The fixture records a side effect and interrupts the response path. A matching retry should return one durable result, while a changed fingerprint under the same key should fail clearly. Exercise simultaneous retries and a server restart if durability is part of the guarantee.

Finally, start two differently configured clients in the same context and check isolation. Record attempt identifiers separately from business command identifiers in non-sensitive logs. This lets a reviewer see three transport attempts for one operation without mistaking them for three intended refunds. Keep payload secrets and authorization headers out of the evidence.

Related practice for failure and retry reasoning

QuestionClient-design follow-up
Send Requests in Batches of Five and Retry Failures After a Per-Request DelayBound outstanding retries and elapsed time.
Implement retry wrapper and interdependent validatorsKeep permanent validation separate from transient failure.
Choose Optimal Network Retry ThresholdExplain the cost of additional attempts.
Build an API aggregator with concurrency and retriesAvoid multiplying attempts across layers.
Debug an Async Payment Refund Function with Retries, Then Make It IdempotentPreserve one operation across uncertain outcomes.

Rehearse the refund exercise with one concrete configuration trace and one lost-response timeline. Explain what the client knows, what the server has committed, and which evidence resolves the gap.

Sources and Further Reading