Skip to content

Conversation

@Piumal1999
Copy link

@Piumal1999 Piumal1999 commented Nov 17, 2025

Purpose

To fix wso2/api-manager#4414

Approach

Samples

N/A

Summary by CodeRabbit

  • Bug Fixes
    • Improved handling for unexpectedly terminated backend connections: richer diagnostic logging, state-aware connection shutdowns, and automatic propagation of faults to error handlers when needed — reducing silent failures and improving system reliability and observability.

@coderabbitai
Copy link

coderabbitai bot commented Nov 17, 2025

Walkthrough

Added a public method endOfInput(NHttpClientConnection) to TargetHandler to handle backend connection termination: logs connection/state, sets state to CLOSED, shuts down the connection, and conditionally forwards an internal send I/O error to the target error handler if response was not completed and a request context exists.

Changes

Cohort / File(s) Change Summary
Backend Connection Termination Handler
modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/TargetHandler.java
Added public void endOfInput(NHttpClientConnection conn) throws IOException that reads current ProtocolState, logs diagnostics, updates state to CLOSED, aggressively shuts down the connection, and if previous state != RESPONSE_DONE and a request message context exists, marks origin as ERROR_HANDLER and forwards SND_IO_ERROR to targetErrorHandler. Added JavaDoc for the method.

Sequence Diagram(s)

sequenceDiagram
    participant Backend
    participant TargetHandler
    participant Connection
    participant TargetErrorHandler

    Backend->>TargetHandler: endOfInput(conn)
    TargetHandler->>TargetHandler: Read ProtocolState & log diagnostics
    TargetHandler->>Connection: Set state -> CLOSED
    TargetHandler->>Connection: Shutdown (close) connection

    alt previous state != RESPONSE_DONE && request msg ctx exists
        TargetHandler->>TargetHandler: Mark internal origin = ERROR_HANDLER
        TargetHandler->>TargetErrorHandler: forward(SND_IO_ERROR, current state)
    else
        TargetHandler->>TargetHandler: No error forwarding
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Verify correctness of state check (previous vs current) and edge cases around RESPONSE_DONE.
  • Confirm proper retrieval and null-safety checks for the request message context.
  • Inspect shutdown approach for aggressive close to ensure no resource leaks.
  • Validate that forwarding via targetErrorHandler preserves expected error metadata and threading behavior.

Poem

🐇 I sniffed the pipe where packets sleep,
A sudden hush — the stream ran deep.
I mark the state, I close the door,
If wings were broken, I warn once more.
Hop, fix, and patch — the gateway keeps.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Description check ❓ Inconclusive The description includes Purpose (with issue link) and Approach sections but omits most required template sections like Goals, Release notes, Documentation, Security checks, and Test environment details. Complete the PR description by adding Goals, Release note, Documentation impact, Security checks confirmation, and Test environment details to meet template requirements.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: adding fault sequence triggering for forceful connection closures via the new endOfInput method.
Linked Issues check ✅ Passed The code changes directly address issue #4414 by implementing fault sequence triggering for forceful connection closures while skipping completed response states to prevent spurious errors.
Out of Scope Changes check ✅ Passed All changes are scoped to the TargetHandler class's endOfInput method, directly addressing the forceful connection closure handling and error propagation outlined in the linked issue.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@Piumal1999 Piumal1999 marked this pull request as ready for review November 17, 2025 15:10
@Piumal1999 Piumal1999 requested a review from chanikag as a code owner November 17, 2025 15:10
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 89a471d and ab28b09.

📒 Files selected for processing (1)
  • modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/TargetHandler.java (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/TargetHandler.java (2)
modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/TargetContext.java (1)
  • TargetContext (34-258)
modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/PassThroughConstants.java (1)
  • PassThroughConstants (19-280)
🔇 Additional comments (1)
modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/TargetHandler.java (1)

1069-1086: Add metrics update and correlation logging to endOfInput() to match the error-handling pattern in exception().

The review comment is valid. Verification confirms:

  1. endOfInput() calls shutdownConnection(conn, true) which invokes conn.shutdown() rather than conn.close(), preventing the closed() callback from being triggered and bypassing the metrics.disconnected() call at line 832.

  2. endOfInput() lacks correlation logging entirely, whereas exception() conditionally logs to correlation log when enabled (lines 1158-1160).

Since endOfInput() represents an error path (unexpected connection termination), it should mirror the telemetry pattern in exception(): add metrics.disconnected() directly and conditionally log to correlation log using logHttpRequestErrorInCorrelationLog() when PassThroughCorrelationConfigDataHolder.isEnable() is true.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ab28b09 and f3739f9.

📒 Files selected for processing (1)
  • modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/TargetHandler.java (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/TargetHandler.java (2)
modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/TargetContext.java (1)
  • TargetContext (34-258)
modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/PassThroughConstants.java (1)
  • PassThroughConstants (19-280)

Comment on lines 1069 to 1087
public void endOfInput(NHttpClientConnection conn) throws IOException {
conn.close();

ProtocolState state = TargetContext.getState(conn);
log.warn("Connection ended unexpectedly" +
", " + getConnectionLoggingInfo(conn) +
", State: " + state + ".");
TargetContext.updateState(conn, ProtocolState.CLOSED);
targetConfiguration.getConnections().shutdownConnection(conn, true);
MessageContext requestMsgCtx = TargetContext.get(conn).getRequestMsgCtx();
if (state != ProtocolState.RESPONSE_DONE && requestMsgCtx != null) {
requestMsgCtx.setProperty(PassThroughConstants.INTERNAL_EXCEPTION_ORIGIN,
PassThroughConstants.INTERNAL_ORIGIN_ERROR_HANDLER);
targetErrorHandler.handleError(requestMsgCtx,
ErrorCodes.SND_IO_ERROR,
"Error in Sender",
null,
state);
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

Verify pipe notification and metrics handling.

The implementation correctly addresses the PR objective by conditionally triggering the error handler only when state != ProtocolState.RESPONSE_DONE, preventing spurious error logs when the response is already complete.

However, comparing this with similar event handlers in the file (e.g., closed(), timeout(), exception()), I notice that those methods call:

  1. informReaderError() or informWriterError() based on state to notify pipes that an error occurred
  2. Metrics methods like metrics.disconnected() or metrics.incrementFaultsReceiving()

The endOfInput method doesn't make these calls. While shutdownConnection(conn, true) and targetErrorHandler.handleError() might handle this internally, it's worth verifying that:

  • Pipes are properly notified so that threads waiting on them don't hang
  • Metrics are correctly updated for monitoring purposes

Run the following script to check how informReaderError and informWriterError are used in other event handlers and whether shutdownConnection handles pipe cleanup:


🏁 Script executed:

#!/bin/bash
# Check usage patterns of pipe notification and metrics in event handlers

echo "=== Event handlers that call informReaderError or informWriterError ==="
rg -n "def (closed|timeout|exception|endOfInput)" -A 50 | rg "(informReaderError|informWriterError|metrics\.)"

echo -e "\n=== Check if shutdownConnection handles pipe cleanup ==="
rg -n "shutdownConnection" -B 2 -A 2

echo -e "\n=== Check targetErrorHandler.handleError implementation ==="
ast-grep --pattern 'class TargetErrorHandler {
  $$$
  handleError($$$) {
    $$$
  }
  $$$
}'

Length of output: 37585


Let me search for the complete implementations in the codebase to verify the pattern.

Let me correct that and run with the repository:



🏁 Script executed:

#!/bin/bash
# Find the closed() and exception() method implementations in TargetHandler
echo "=== TargetHandler.closed() method implementation ==="
rg -n "public void closed" --type java -A 80 modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/TargetHandler.java | head -100

echo -e "\n=== TargetHandler.exception() method implementation (first 50 lines) ==="
rg -n "public void exception" --type java -A 50 modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/TargetHandler.java | head -60

Length of output: 10675


🏁 Script executed:

#!/bin/bash
# Extract the closed() method from TargetHandler
echo "=== TargetHandler.closed() method ==="
sed -n '/^\s*public void closed(NHttpClientConnection/,/^\s*public void/p' modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/TargetHandler.java | head -100

echo -e "\n=== TargetHandler.exception() method (first 60 lines) ==="
sed -n '/^\s*public void exception(NHttpClientConnection/,/^\s*public void/p' modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/TargetHandler.java | head -100

Length of output: 13628


Add pipe notifications and metrics update to prevent thread hangs and incomplete monitoring.

Verification shows that endOfInput() is missing critical operations found in similar event handlers:

  1. Missing pipe notifications: Both closed() (lines 781, 794) and exception() (lines 1095, 1106) call informWriterError() or informReaderError() for REQUEST_HEAD/REQUEST_BODY and RESPONSE_HEAD/RESPONSE_BODY states respectively. These notify the pipes and prevent threads from hanging. The endOfInput() method omits these calls entirely.

  2. Missing metrics update: The closed() method calls metrics.disconnected() (line 832) for all closures. The endOfInput() method has no equivalent metrics call.

The pattern from existing handlers is: Always notify pipes for relevant states, but conditionally call error handler based on state != RESPONSE_DONE. Currently, endOfInput() only does the conditional error handler part.

Fix required: Add pipe notifications and metrics update similar to closed() and exception() methods.

🤖 Prompt for AI Agents
In
modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/TargetHandler.java
around lines 1069 to 1087, endOfInput(...) currently logs, updates state, shuts
down the connection and conditionally invokes the error handler, but it omits
the pipe notifications and metrics update used by closed() and exception();
update endOfInput() to: call the same pipe notification helpers used elsewhere
(invoke informWriterError() for REQUEST_HEAD/REQUEST_BODY and
informReaderError() for RESPONSE_HEAD/RESPONSE_BODY as appropriate) before/after
updating state so waiting threads are unblocked, invoke metrics.disconnected()
to record the disconnect, and keep the existing conditional call to
targetErrorHandler only when state != RESPONSE_DONE; ensure ordering matches
closed()/exception() (notify pipes, update metrics, update state/shutdown
connection, then conditional error handler).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants