You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@livy.apache.org by "Nilesh Rathi (Jira)" <ji...@apache.org> on 2026/07/28 12:21:00 UTC

[jira] [Created] (LIVY-1062) Livy Java HTTP client does not follow redirects for POST/DELETE in HA mode

Nilesh Rathi created LIVY-1062:
----------------------------------

             Summary: Livy Java HTTP client does not follow redirects for POST/DELETE in HA mode
                 Key: LIVY-1062
                 URL: https://issues.apache.org/jira/browse/LIVY-1062
             Project: Livy
          Issue Type: Bug
            Reporter: Nilesh Rathi


When Apache Livy runs in High Availability (HA) mode, passive (standby) Livy server instances redirect incoming client requests to the active leader using HTTP {{307 Temporary Redirect}} responses with a {{Location}} header pointing to the active server.

The Livy Java HTTP client ({{LivyConnection}} in {{client-http}}) does not handle these redirects for {{POST}} and {{DELETE}} requests. Apache HttpClient does not automatically follow redirects for non-idempotent methods, and {{LivyConnection.sendRequest()}} treats any non-200 response as a fatal error. As a result, applications using the Livy Job API (Java/Scala programmatic client) fail when their initial connection lands on a standby node.
h3. Problem

In HA deployments, clients often connect to a load-balanced or round-robin Livy endpoint. When a {{POST}} (e.g., session creation, job submission) or {{DELETE}} (e.g., session/job cancellation) request reaches a passive Livy instance, the server responds with HTTP 307 and a {{Location}} header redirecting to the active leader. {{LivyConnection}} does not follow this redirect and instead throws an {{IOException}}.
h3. Root Cause

In {{client-http/src/main/java/org/apache/livy/client/http/LivyConnection.java}}, the {{sendRequest()}} method executes the HTTP request and only accepts {{HTTP 200 (SC_OK)}} as success. Any other status code (including {{307 Temporary Redirect}}) causes an {{IOException}} to be thrown:

{code:java}
int status = (res.getStatusLine().getStatusCode() / 100) * 100;
if (status == HttpStatus.SC_OK) {
  // success
} else {
  throw new IOException(String.format("%s: %s", res.getStatusLine().getReasonPhrase(), error));
}
{code}

Apache HttpClient follows redirects automatically for {{GET}} requests but *not* for {{POST}} or {{DELETE}}. Since the Livy Job API relies heavily on {{POST}} (submit jobs, create sessions) and {{DELETE}} (cancel jobs, stop sessions), HA redirect handling is broken for the primary programmatic client use cases.
h3. Steps to Reproduce
 # Deploy Livy in HA mode with multiple Livy server instances (active/passive or multi-active with leader redirect).
 # Configure a client application using the Livy Java HTTP client ({{LivyClientBuilder}} / Job API).
 # Point the client at a Livy endpoint where the initial request may land on a passive/standby instance (e.g., via load balancer or by connecting directly to a known passive node).
 # Submit a job or create a session via {{POST}}, or cancel via {{DELETE}}.
 # Observe the client-side failure.
h3. Expected Behavior

{{LivyConnection}} should transparently follow HTTP {{307}} (and {{302}}) redirects for all supported HTTP methods ({{GET}}, {{POST}}, {{DELETE}}), re-issuing the original request (including request body and authentication headers) to the URL specified in the {{Location}} header. The client should return the final successful response from the active Livy server.
h3. Actual Behavior

The client throws an exception on receiving a redirect response:

{code:java}
java.util.concurrent.ExecutionException: java.lang.RuntimeException: java.io.IOException: Temporary Redirect: <redirect body>
{code}
h3. Impact

* Java/Scala applications using the Livy Job API cannot operate reliably in HA environments.
* Any workload that submits Spark jobs programmatically via {{LivyClient}} (e.g., custom ETL pipelines, integration tests, embedded Spark job runners) fails when the initial TCP connection reaches a non-leader Livy instance.
* {{GET}} requests may appear to work in some cases because HttpClient follows GET redirects by default, masking the problem for read-only operations while write operations consistently fail.
h3. Proposed Fix

Update {{LivyConnection.sendRequest()}} to detect HTTP {{307}} / {{302}} redirect responses, extract the {{Location}} header, and re-issue the original request to the redirect target. The fix should:

* Preserve the original HTTP method, request body, and headers (including {{X-Requested-By}} and authentication credentials).
* Support SPNEGO/Kerberos re-authentication on the redirected request.
* Limit redirect loops (e.g., max redirect count) to prevent infinite loops.
* Add unit tests covering redirect handling for {{POST}} and {{DELETE}}.
h3. Related Work

* [LIVY-718|https://issues.apache.org/jira/browse/LIVY-718] — Support multi-active high availability in Livy
* [LIVY-744|https://issues.apache.org/jira/browse/LIVY-744] — Livy Job API support multi-active HA
* Livy HA design uses HTTP 307 redirects for request routing between cluster nodes (see [LIVY-698|https://issues.apache.org/jira/browse/LIVY-698]).



--
This message was sent by Atlassian Jira
(v8.20.10#820010)