Repository navigation
[FLINK-40278][connector-http] Document and test that HTTP sink retries resend the whole batch - #57
Conversation
0d77851 to
cee73a9
Compare
6a97e7f to
6fe47be
Compare
6fe47be to
28595cc
Compare
|
in general - if we retry the whole batch is it possible for some of them to be accepted? So retrying would produce duplicates - can we know which event(s) needs to be retried? |
| response that is not successful or ignored is not retried and fails the job. A request that still fails with a retryable | ||
| error after the last retry also fails the job. | ||
|
|
||
| In batch submission mode, each HTTP request carries several records and gets one response status, which applies to every |
There was a problem hiding this comment.
can we get more granular information?
There was a problem hiding this comment.
Not today: the sink only reads the status code. Per-record results need a parser for the endpoint's response body, out of scope for this ticket. A partly applied batch is resent in full.
There was a problem hiding this comment.
Confirming what Martijn said: the sink classifies a response from its status code only, so it cannot tell which records of a batch the server applied. Per-record retry needs a response-body parser for the target, which is out of scope here. The docs state the limitation and recommend an idempotent endpoint for that case.
| fails all of them. The sink does not retry individual records inside a batch. Use an idempotent endpoint if retried | ||
| records must not be applied twice. When one flush is split into several HTTP requests (because of | ||
| `http.sink.request.batch.size` or different HTTP methods), each response applies only to the records in its own request. | ||
| Retried records are batched again, so they can be grouped into different HTTP requests than in the first attempt. |
There was a problem hiding this comment.
have you manually tested this?
There was a problem hiding this comment.
Checked locally with http.sink.request.batch.size 2 and three records: only the failed request's records are resent. Please add a test, nothing in the PR covers this yet.
There was a problem hiding this comment.
@davidradl yes, both with unit tests and end to end.
@MartijnVisser added two tests in JavaNetSinkHttpClientTest that go through the real BatchRequestSubmitter:
batchModeRetriesOnlyTheFailedRequestWhenFlushIsSplit: batch size 2, three records. The HTTP requests are[1,2]-> 500,[3]-> 200, then only[1,2]is resent.batchModeRegroupsRetriedEntriesIntoNewHttpRequests: POST, PUT, POST. The two failed POST records come back as one request on retry.
Both record the entries of every HTTP request through the post-request callback and compare by identity.
The same scenarios also run end to end in a Flink mini-cluster against an embedded HTTP server in bharathgunapati/flink-http-sink-examples (DataStreamHttpSinkIT, commit 699e9ee). Server log:
POST /split-batch -> 500 body=[{"id":1},{"id":2}]
POST /split-batch -> 200 body=[{"id":3}]
POST /split-batch -> 200 body=[{"id":1},{"id":2}]
POST /regroup -> 500 body=[{"id":1}]
PUT /regroup -> 200 body=[{"id":2,"method":"PUT"}]
POST /regroup -> 500 body=[{"id":3}]
POST /regroup -> 200 body=[{"id":1},{"id":3}]
MartijnVisser
left a comment
There was a problem hiding this comment.
Thanks for the PR. The new batch tests fail when BatchRequestSubmitter rebuilds the entries, so the identity checks work. Can you add the AI disclosure from the PR template (FLINK-40758)?
| Retries are disabled by default: `http.sink.max-retries` defaults to `0`, so the first failed request fails the job. | ||
|
|
||
| When `http.sink.max-retries` is greater than `0`, the sink retries requests that fail before a response is received (for | ||
| example, connection errors) and responses whose status code is listed in `http.sink.retry-codes`. The delay between |
There was a problem hiding this comment.
With the legacy http.sink.error.code properties, no status code is retried, only failures without a response. I think that needs a sentence here, on all four pages.
There was a problem hiding this comment.
Good catch. Added a paragraph on all four pages: with the legacy http.sink.error.code / http.sink.error.code.exclude properties no status code is retried, a code in the error list fails the job, every other code is success, and only requests that fail before a response is retried. That matches HttpSinkResponseClassifier, which returns only SUCCESS or FATAL_FAILURE on the legacy path.
28595cc to
8d59f21
Compare
Cover the batch retry semantics documented in apache/flink-connector-http#57 end to end: a flush split by http.sink.request.batch.size retries only the records of the failed HTTP request, and retried records are regrouped into new HTTP requests. - MockHttpServer: fail the first request whose body contains a marker and answer 200 otherwise, so a failure follows a record rather than a request position (requests of one flush are sent concurrently). Drop dead code. - DataStreamHttpSinkIT: two new scenarios; records tagged with "method":"PUT" are sent with PUT so one test can mix methods. - DataStreamHttpSinkExample: runnable /split-batch-retry demo. - CI and README: build the connector from FLINK-40278-sink-batch-retry-semantics. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
Thanks for the reviews. Addressed in the latest push:
@davidradl on the duplicates question: yes, if the server applied part of a batch before answering 500, the retry resends the whole batch. The sink cannot know which records were applied from a status code alone, so the docs ask for an idempotent endpoint when that matters. The CI run for the new head is waiting for workflow approval. Could one of you approve it? |
MartijnVisser
left a comment
There was a problem hiding this comment.
Thanks, the split-flush tests and the legacy error-code paragraph cover what I asked. Please replace the Co-Authored-By trailer with the Generated-by: line from the PR description, as the contribution guide asks.
…s resend the whole batch Generated-by: Cursor (auto mode) for the initial change; Claude Code (Claude Fable 5.1) for the review follow-ups
8d59f21 to
b4e74c7
Compare
Purpose of the change
https://issues.apache.org/jira/browse/FLINK-40278
Define, document, and test HTTP sink retry semantics for batch submission mode. The retry behaviour itself was implemented in FLINK-40277 (#54); this PR makes it explicit and locks it in with tests. Sink runtime code is unchanged.
In batch submission mode, each HTTP request carries several records and gets one response status:
Partial per-record retry is out of scope; it would need a response processor that can parse target-specific per-record results.
Brief change log
http.sink.max-retries=0), which failures are retried, that with the legacyhttp.sink.error.codeproperties no status code is retried (only requests without a response), and that one flush split into several HTTP requests is handled per request.JavaNetSinkHttpClientTestcases that run through the realPerRequestSubmitterandBatchRequestSubmitter:http.sink.request.batch.sizeretries only the records of the failed HTTP request;HttpSinkRequestEntryinstances (identity, not equality), so retries reuse the original entries rather than reconstructed request bytes. The split-flush tests record the entries of every HTTP request through the post-request callback.@AfterEachso a failed assertion does not leak executors.Verifying this change
mvn -pl flink-connector-http -DskipITs -Dskip.archunit=true -Dtest=JavaNetSinkHttpClientTest,HttpSinkClientWithRetryTest,BatchRequestSubmitterTest,HttpSinkWriterTest test(39 tests, all pass)mvn -pl flink-connector-http spotless:check checkstyle:checkMutation check: making
BatchRequestSubmitterwrap each entry in a newHttpSinkRequestEntryfails the four batch identity tests, so the identity assertions are effective.Impact and documentation
Was generative AI tooling used to co-author this PR?
Generated-by: Cursor (auto mode) for the initial change; Claude Code (Claude Fable 5.1) for the review follow-ups