diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 3ad09d5afe..0d047a0717 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -199,8 +199,9 @@ jobs: with: type: specs + # Always download the utils for js, in case they changed we want to include them in the zip - name: Download JavaScript utils artifacts - if: ${{ matrix.client.language == 'javascript' && steps.cache.outputs.cache-hit != 'true' }} + if: ${{ matrix.client.language == 'javascript' }} uses: ./.github/actions/restore-artifacts with: type: js_utils diff --git a/clients/algoliasearch-client-java-2/algoliasearch-core/src/main/java/com/algolia/exceptions/AlgoliaRetriesExceededException.java b/clients/algoliasearch-client-java-2/algoliasearch-core/src/main/java/com/algolia/exceptions/AlgoliaRetriesExceededException.java new file mode 100644 index 0000000000..aed6ac50c2 --- /dev/null +++ b/clients/algoliasearch-client-java-2/algoliasearch-core/src/main/java/com/algolia/exceptions/AlgoliaRetriesExceededException.java @@ -0,0 +1,22 @@ +package com.algolia.exceptions; + +/** + * Exception thrown when an error occurs during the waitForTask strategy. For example: maximum + * number of retry exceeded + */ +public class AlgoliaRetriesExceededException extends AlgoliaRuntimeException { + + public static final long serialVersionUID = 1L; + + public AlgoliaRetriesExceededException(String message, Throwable cause) { + super(message, cause); + } + + public AlgoliaRetriesExceededException(String message) { + super(message); + } + + public AlgoliaRetriesExceededException(Throwable cause) { + super(cause); + } +} diff --git a/clients/algoliasearch-client-java-2/algoliasearch-core/src/main/java/com/algolia/utils/TaskUtils.java b/clients/algoliasearch-client-java-2/algoliasearch-core/src/main/java/com/algolia/utils/TaskUtils.java new file mode 100644 index 0000000000..42a18395a9 --- /dev/null +++ b/clients/algoliasearch-client-java-2/algoliasearch-core/src/main/java/com/algolia/utils/TaskUtils.java @@ -0,0 +1,51 @@ +package com.algolia.utils; + +import com.algolia.exceptions.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.function.IntUnaryOperator; +import java.util.function.Predicate; +import java.util.function.Supplier; + +public class TaskUtils { + + public static final int DEFAULT_MAX_TRIAL = 50; + public static final IntUnaryOperator DEFAULT_TIMEOUT = (int retries) -> { + return Math.min(retries * 200, 5000); + }; + + public static void retryUntil( + Supplier> func, + Predicate validate, + int maxTrial, + IntUnaryOperator timeout + ) throws AlgoliaRuntimeException { + int retryCount = 0; + while (retryCount < maxTrial) { + try { + TResponse resp = func.get().get(); + if (validate.test(resp)) { + return; + } + } catch (InterruptedException | ExecutionException e) { + // if the task is interrupted, just return + return; + } + try { + Thread.sleep(timeout.applyAsInt(retryCount)); + } catch (InterruptedException ignored) { + // Restore interrupted state... + Thread.currentThread().interrupt(); + } + + retryCount++; + } + throw new AlgoliaRetriesExceededException( + "The maximum number of trials exceeded. (" + + (retryCount + 1) + + "/" + + maxTrial + + ")" + ); + } +} diff --git a/clients/algoliasearch-client-javascript/packages/client-common/src/createRetryablePromise.ts b/clients/algoliasearch-client-javascript/packages/client-common/src/createRetryablePromise.ts index 73bb69e73f..990c3a6fb2 100644 --- a/clients/algoliasearch-client-javascript/packages/client-common/src/createRetryablePromise.ts +++ b/clients/algoliasearch-client-javascript/packages/client-common/src/createRetryablePromise.ts @@ -1,5 +1,9 @@ import type { CreateRetryablePromiseOptions } from './types/CreateRetryablePromise'; +export const DEFAULT_MAX_TRIAL = 50; +export const DEFAULT_TIMEOUT = (retryCount: number): number => + Math.min(retryCount * 200, 5000); + /** * Return a promise that retry a task until it meets the condition. * @@ -12,8 +16,8 @@ import type { CreateRetryablePromiseOptions } from './types/CreateRetryablePromi export function createRetryablePromise({ func, validate, - maxTrial = 10, - timeout = (retryCount: number): number => Math.min(retryCount * 10, 1000), + maxTrial = DEFAULT_MAX_TRIAL, + timeout = DEFAULT_TIMEOUT, }: CreateRetryablePromiseOptions): Promise { let retryCount = 0; const retry = (): Promise => { diff --git a/generators/src/main/java/com/algolia/codegen/AlgoliaJavaGenerator.java b/generators/src/main/java/com/algolia/codegen/AlgoliaJavaGenerator.java index b2e39aea23..7f5d6736b8 100644 --- a/generators/src/main/java/com/algolia/codegen/AlgoliaJavaGenerator.java +++ b/generators/src/main/java/com/algolia/codegen/AlgoliaJavaGenerator.java @@ -50,6 +50,10 @@ public Map postProcessOperationsWithModels( Utils.getClientNameKebabCase(results), additionalProperties ); + additionalProperties.put( + "isSearchClient", + Utils.getClientNameKebabCase(results).equals("search") + ); additionalProperties.put( "packageVersion", Utils.getClientConfigField("java", "packageVersion") diff --git a/templates/java/libraries/okhttp-gson/api.mustache b/templates/java/libraries/okhttp-gson/api.mustache index 74033b6e85..df3ba1dc38 100644 --- a/templates/java/libraries/okhttp-gson/api.mustache +++ b/templates/java/libraries/okhttp-gson/api.mustache @@ -13,6 +13,7 @@ import com.algolia.exceptions.*; import com.algolia.utils.retry.CallType; import com.algolia.utils.retry.StatefulHost; import com.algolia.utils.RequestOptions; +import java.util.function.IntUnaryOperator; import java.util.EnumSet; import java.util.Random; @@ -216,5 +217,27 @@ public class {{classname}} extends ApiClient { } {{/optionalParams.0}} {{/operation}} + + {{#isSearchClient}} + public void waitForTask(String indexName, Long taskID, RequestOptions requestOptions, int maxTrial, IntUnaryOperator timeout) { + TaskUtils.retryUntil(() -> { + return this.getTaskAsync(indexName, taskID, requestOptions); + }, (GetTaskResponse task) -> { + return task.getStatus() == TaskStatus.PUBLISHED; + }, maxTrial, timeout); + } + + public void waitForTask(String indexName, Long taskID, RequestOptions requestOptions) { + this.waitForTask(indexName, taskID, requestOptions, TaskUtils.DEFAULT_MAX_TRIAL, TaskUtils.DEFAULT_TIMEOUT); + } + + public void waitForTask(String indexName, Long taskID, int maxTrial, IntUnaryOperator timeout) { + this.waitForTask(indexName, taskID, null, maxTrial, timeout); + } + + public void waitForTask(String indexName, Long taskID) { + this.waitForTask(indexName, taskID, null, TaskUtils.DEFAULT_MAX_TRIAL, TaskUtils.DEFAULT_TIMEOUT); + } + {{/isSearchClient}} } {{/operations}}