Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expands the HTTP interceptor API to include a call back for failed connection attempts #6144

Merged
merged 12 commits into from
Aug 9, 2024

Conversation

SamBarker
Copy link
Contributor

@SamBarker SamBarker commented Jul 17, 2024

Description

Expands the HTTP interceptor API to include a call back for failed connection attempts as discussed in #6143

Fixes #6143

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • Feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change
  • Chore (non-breaking change which doesn't affect codebase;
    test, version modification, documentation, etc.)

Depends on the definition of breaking change as it adds a new default method to an interface which could be seen as a breaking change for any implementation that already has that method defined but practically speaking this is backwards compatible.

Checklist

  • Code contributed by me aligns with current project license: Apache 2.0
  • I Added CHANGELOG entry regarding this change
  • I have implemented unit tests to cover my changes
  • I have added/updated the javadocs and other documentation accordingly
  • No new bugs, code smells, etc. in SonarCloud report
  • I tested my code in Kubernetes
  • I tested my code in OpenShift

@SamBarker SamBarker changed the title Failing test demonstrating https://github.com/fabric8io/kubernetes-client/issues/6143 Failing test demonstrating #6143 Jul 17, 2024
@SamBarker SamBarker force-pushed the afterFailureInvocation branch 2 times, most recently from bb6746c to c48e929 Compare July 21, 2024 23:59
@SamBarker SamBarker changed the title Failing test demonstrating #6143 Expands the HTTP interceptor API to include a call back for failed connection attempts Jul 22, 2024
@SamBarker SamBarker force-pushed the afterFailureInvocation branch 2 times, most recently from 0e21fe0 to cbee038 Compare July 22, 2024 02:45
@@ -103,6 +103,11 @@ public void onContent(Response response, ByteBuffer content, Callback callback)
}
}

@Override
public void onFailure(Response response, Throwable failure) {
asyncResponse.completeExceptionally(failure);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is the part of the PR I'm most un-sure of as I think it implies that the jetty implementation never completed futures on connection failure. Instead it relied on timeouts to handle those failures, but I could be very wrong about that.

Copy link
Member

Choose a reason for hiding this comment

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

I can't remember, but I do recall using the Adapter to avoid implementing all methods.
It's certainly strange that the onFailure wasn't implemented before. However, the HttpClient behavior did change a little after the original implementation (especially the retries part).

Anyway, it does seem OK to have this.

Copy link
Contributor

Choose a reason for hiding this comment

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

It looks like overriding onComplete ensured timely completion - but does not have appropriate exception handling.

What we are probably looking for here instead is using onComplete Result.getRequestFailure - that maps most closely to these types of exceptions. There is also Result.getResponseFailure which should be the same as what is passed to onFailure.

Copy link
Contributor Author

@SamBarker SamBarker Jul 24, 2024

Choose a reason for hiding this comment

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

Oh this gets fun 😅

Updating onComplete to respect Result.isSucceeded() or Result.isFailed() causes the expectContinue test to fail, because Jetty considers a 404 in response to a request with Expect=100-continue to be a failure. So i've tried adding server.expect().post().withPath("/post-expect-continue").andReply(100, request -> "").always(); which causes the server to reply appropriately to the POST request. However that breaks the expectContinue test for jetty, OkHttp and VertX (there doesn't seem to be a JDK version 👀 ) clients tests 😢 .

In the jetty case the test now fails because the response is considered pending and there is no further demand so the request future never completes. I haven't debugged the others to work out whats going wrong but I suspect its something similar.

Reading MDN on 100-continue suggests the jetty implementation is wrong as it attaches the body to the POST request at the same time as the Expect=100-continue header. Whereas MDN suggests that it should send Expect=100-continue and wait for the response to that before continuing by sending the body.

I'm nothing like close enough to the details of the Kube API server to understand if 100-continue is commonly used or if it has a problem with including the POST body on the initial request. However this is starting to feel like a rabbit hole and not really in scope for this PR and thus what the implications of this are in practice.

Thoughts @manusa, @shawkins ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ahh the JDK client explicitly disables the expectContinue test.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Reading MDN on 100-continue suggests the jetty implementation is wrong as it attaches the body to the POST request at the same time as the Expect=100-continue header. Whereas MDN suggests that it should send Expect=100-continue and wait for the response to that before continuing by sending the body.

After further debugging the jetty Impl is right, jetty handles delaying the body if the Expect header is set but I'm still not seeing the request complete.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hmm turns out I was very wrong about what was going on after much debugging I have
https://github.com/fabric8io/kubernetes-client/pull/6197/files

Which changes the default socketPolicy for the mockWebserver to EXPECT_CONTINUE from KEEP_OPEN. I haven't found a way to make it conditional on the headers as its too late by the time dispatch is called. I'm not at all sure what implications that change has.

I'm happy to merge that PR into this one if preferred but I think they are really independent. I'm happy to clean up that PR and its description and or raise an issue to cover it if the consensus is to keep it independent.

Copy link
Member

Choose a reason for hiding this comment

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

Nice work, I think it's better to keep them separate.

@@ -170,6 +172,28 @@ public CompletableFuture<Boolean> afterFailure(BasicBuilder builder, HttpRespons
}
}

@Test
@DisplayName("afterFailure (HTTP), invoked when remote server offline")
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This commit could arguably be dropped but the test evolves in the next commit with the fix.

Comment on lines 113 to 115
if (throwable instanceof CompletionException) {
throw (CompletionException) throwable;
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

sonar is complaining this branch is untested, but I can't work out a way to inject a CompletionException. Any pointers gratefully received.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Came up with SamBarker@43f88fa which does trigger the branch using the Jetty client.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

apparently not according to sonar. It seemed to work in the debugger locally.

Copy link
Member

Choose a reason for hiding this comment

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

Note that the sonar coverage is per-module. I'm not sure if this might affect the way coverage is computed since the Abstract test class is hosted in a different module.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Urgh yeah I hadn't thought about the multiple modules pushing in different directions. Sonar only reports a single number on the StandardHttpClient so a bit hard to know. I suspect on balance its probably better to have the test than not but I only added it to try and pass the coverage stats for the PR so not wedded to it as the core flows are tested.

@SamBarker SamBarker force-pushed the afterFailureInvocation branch 2 times, most recently from 43f88fa to 99cacc3 Compare July 22, 2024 21:29
@SamBarker SamBarker marked this pull request as ready for review July 22, 2024 21:31
@SamBarker SamBarker force-pushed the afterFailureInvocation branch from 21db115 to 8d522ac Compare July 24, 2024 09:46
Copy link
Member

@manusa manusa left a comment

Choose a reason for hiding this comment

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

Besides the Javadoc issue I think everything else looks OK.

@shawkins any comments?

BTW, even though this is adding a feature, I'm going to consider it as a bug fix since it's addressing the lack of feature parity of Fabric8-OkHttp interceptors.

This way we can include it as part of #6097 and release it in 6.13.2

Copy link
Contributor

@shawkins shawkins left a comment

Choose a reason for hiding this comment

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

Overall looks good, but we may need more refinement of Jetty exception handling.

@@ -103,6 +103,11 @@ public void onContent(Response response, ByteBuffer content, Callback callback)
}
}

@Override
public void onFailure(Response response, Throwable failure) {
asyncResponse.completeExceptionally(failure);
Copy link
Contributor

Choose a reason for hiding this comment

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

It looks like overriding onComplete ensured timely completion - but does not have appropriate exception handling.

What we are probably looking for here instead is using onComplete Result.getRequestFailure - that maps most closely to these types of exceptions. There is also Result.getResponseFailure which should be the same as what is passed to onFailure.

@SamBarker
Copy link
Contributor Author

BTW, even though this is adding a feature, I'm going to consider it as a bug fix since it's addressing the lack of feature parity of Fabric8-OkHttp interceptors.
This way we can include it as part of #6097 and release it in 6.13.2

Sounds great from my POV

@SamBarker SamBarker force-pushed the afterFailureInvocation branch from 95e325f to f9f1042 Compare July 24, 2024 22:28
@SamBarker
Copy link
Contributor Author

I plan to clean this up once #6197 is merged, but I think the coverage issues will go away once thats merged.

@manusa
Copy link
Member

manusa commented Aug 8, 2024

Hi @SamBarker,
#6197 is finally in. Is there something else left to do on this PR? Shall we merge it too?

…pletionException.

This happens in the Jetty implementation but  gets wrapped in an IOException by the OkHttp impl but this should be enough for the coverage checker.
… so its invoked when an established websocket connection fails
…ed up tests.

Rather than waiting ~20s to give up retrying.
@SamBarker SamBarker force-pushed the afterFailureInvocation branch from f9f1042 to 13070a6 Compare August 8, 2024 21:26
@SamBarker SamBarker force-pushed the afterFailureInvocation branch from 13070a6 to dc27f5e Compare August 8, 2024 21:31
Really just making the coverage checker happy.
@SamBarker SamBarker force-pushed the afterFailureInvocation branch from 0063e1e to e9e4b2c Compare August 8, 2024 23:44
@SamBarker SamBarker force-pushed the afterFailureInvocation branch from c49c1c5 to b8b79d4 Compare August 9, 2024 00:24
Copy link

sonarqubecloud bot commented Aug 9, 2024

@SamBarker
Copy link
Contributor Author

Hi @SamBarker,

#6197 is finally in. Is there something else left to do on this PR? Shall we merge it too?

I've added an extra commit to get the sonar coverage report passing so yes! Let's get this merged.

Any info on a timeline for the next 6.13 release?

@SamBarker SamBarker requested a review from manusa August 9, 2024 04:21
@manusa
Copy link
Member

manusa commented Aug 9, 2024

Any info on a timeline for the next 6.13 release?

I was just waiting for this one (#6097), so probably in a couple of hours or early Monday.

Copy link
Member

@manusa manusa left a comment

Choose a reason for hiding this comment

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

LGTM, thx!

@manusa manusa added this to the 7.0.0 milestone Aug 9, 2024 — with automated-tasks
@manusa manusa merged commit 8147542 into fabric8io:main Aug 9, 2024
21 checks passed
@SamBarker SamBarker deleted the afterFailureInvocation branch August 11, 2024 21:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Interceptor not invoked when connection refused
4 participants