-
Notifications
You must be signed in to change notification settings - Fork 44
Ingest async implementation #430
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
base: master
Are you sure you want to change the base?
Changes from all commits
05e455f
2bb77d2
a078aed
00df901
ad37af0
5ec845e
7493e09
d9d8760
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,22 +4,36 @@ All notable changes to this project will be documented in this file. | |
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), | ||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). | ||
|
||
## [UNRELEASED] | ||
|
||
### Changed | ||
|
||
- [BREAKING] All synchronous queued and streaming ingestion APIs now delegate to their asynchronous counterparts | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there any public api that broke and no longer available? |
||
internally and block for results. | ||
- [BREAKING] Streaming client no longer check for blob size and if it exists. | ||
### Added | ||
- The SDK now provides Reactor Core-based asynchronous APIs for all queued and streaming ingestion endpoints, | ||
enabling non-blocking operations. | ||
|
||
## [6.0.1] | ||
|
||
### Added | ||
- The SDK now provides Reactor Core-based asynchronous APIs for all query, management, streaming query/ingestion (StreamingClient) endpoints, | ||
enabling non-blocking operations. You can read more about Reactor Core and [Mono type here](https://projectreactor.io/docs/core/release/api/). | ||
- `ConnectionStringBuilder` now supports keywords without regards to spaces or case. It now supports `toString()` that prints a canonical connection string, with censored secrets by default. | ||
|
||
### Changed | ||
- [BREAKING] All synchronous query/management, streaming query/ingestion (StreamingClient) APIs now delegate to their asynchronous counterparts | ||
internally and block for results. | ||
- [BREAKING] * Make ManagedStreamingQueuingPolicy internal, expose just a factor | ||
* Dont allow users to pass raw data size, provide it only if we have it | ||
- [BREAKING] Make ManagedStreamingQueuingPolicy internal, expose just a factor | ||
- [BREAKING] Don't allow users to pass raw data size, provide it only if we have it | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Retroactively changing the 6.0.1 changelogs? maybe another PR? |
||
|
||
- [BREAKING] Removing max keep alive from HttpClientPropertiesBuilder. | ||
### Fixed | ||
- Fixed edge cases in query timeouts. | ||
- Long Queries would time out after 2 minutes. Remove keep alive timeout to fix. | ||
|
||
|
||
## [6.0.0-ALPHA-01] - 2024-11-27 | ||
### Added | ||
- A new policy heuristic for choosing between queuing and streaming in Managed streaming client. A policy can be configured | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,7 @@ | |
import java.lang.invoke.MethodHandles; | ||
import java.time.Duration; | ||
import java.util.List; | ||
import java.util.function.Predicate; | ||
|
||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
@@ -12,7 +13,7 @@ | |
import reactor.util.annotation.Nullable; | ||
import reactor.util.retry.Retry; | ||
|
||
public class ExponentialRetry<E1 extends Throwable, E2 extends Throwable> { | ||
public class ExponentialRetry { | ||
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); | ||
|
||
private final int maxAttempts; | ||
|
@@ -37,50 +38,25 @@ public ExponentialRetry(ExponentialRetry other) { | |
this.maxJitterSecs = other.maxJitterSecs; | ||
} | ||
|
||
// Caller should throw only permanent errors, returning null if a retry is needed | ||
public <T> T execute(KustoCheckedFunction<Integer, T, E1, E2> function) throws E1, E2 { | ||
for (int currentAttempt = 0; currentAttempt < maxAttempts; currentAttempt++) { | ||
log.info("execute: Attempt {}", currentAttempt); | ||
|
||
try { | ||
T result = function.apply(currentAttempt); | ||
if (result != null) { | ||
return result; | ||
} | ||
} catch (Exception e) { | ||
log.error("execute: Error is permanent, stopping", e); | ||
throw e; | ||
} | ||
|
||
double currentSleepSecs = sleepBaseSecs * (float) Math.pow(2, currentAttempt); | ||
double jitterSecs = (float) Math.random() * maxJitterSecs; | ||
double sleepMs = (currentSleepSecs + jitterSecs) * 1000; | ||
|
||
log.info("execute: Attempt {} failed, trying again after sleep of {} seconds", currentAttempt, sleepMs / 1000); | ||
|
||
try { | ||
Thread.sleep((long) sleepMs); | ||
} catch (InterruptedException e) { | ||
Thread.currentThread().interrupt(); | ||
throw new RuntimeException("execute: Interrupted while sleeping", e); | ||
} | ||
} | ||
|
||
return null; | ||
} | ||
|
||
/** | ||
* Creates a retry mechanism with exponential backoff and jitter. | ||
* | ||
* @param retriableErrorClasses A list of error classes that are considered retriable. If null, | ||
* the method does not retry. | ||
* @param filter A filter to use. Default is retrying retriable errors. | ||
* @return A configured {@link Retry} instance | ||
*/ | ||
public Retry retry(@Nullable List<Class<? extends Throwable>> retriableErrorClasses) { | ||
public Retry retry(@Nullable List<Class<? extends Throwable>> retriableErrorClasses, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: the only time we use the first param is in a test. Do we really need it? |
||
@Nullable Predicate<? super Throwable> filter) { | ||
if (retriableErrorClasses != null && filter != null) { | ||
throw new IllegalArgumentException("Cannot specify both retriableErrorClasses and filter"); | ||
} | ||
|
||
Predicate<? super Throwable> filterToUse = filter == null ? throwable -> shouldRetry(throwable, retriableErrorClasses) : filter; | ||
return Retry.backoff(maxAttempts, Duration.ofSeconds((long) sleepBaseSecs)) | ||
.maxBackoff(Duration.ofSeconds(30)) | ||
.jitter(maxJitterSecs) | ||
.filter(throwable -> shouldRetry(throwable, retriableErrorClasses)) | ||
.filter(filterToUse) | ||
.doAfterRetry(retrySignal -> { | ||
long currentAttempt = retrySignal.totalRetries() + 1; | ||
log.info("Attempt {} failed.", currentAttempt); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should it have any effects for the user?
I think a big thing is the exception thanges. IDK if we mention it anywhere