diff --git a/plugins/nf-azure/src/main/nextflow/cloud/azure/batch/AzHelper.groovy b/plugins/nf-azure/src/main/nextflow/cloud/azure/batch/AzHelper.groovy index 751678294f..ba4ba6cd71 100644 --- a/plugins/nf-azure/src/main/nextflow/cloud/azure/batch/AzHelper.groovy +++ b/plugins/nf-azure/src/main/nextflow/cloud/azure/batch/AzHelper.groovy @@ -28,6 +28,8 @@ import com.azure.storage.blob.sas.BlobContainerSasPermission import com.azure.storage.blob.sas.BlobSasPermission import com.azure.storage.blob.sas.BlobServiceSasSignatureValues import com.azure.storage.common.StorageSharedKeyCredential +import com.azure.storage.common.policy.RequestRetryOptions +import com.azure.storage.common.policy.RetryPolicyType import com.azure.storage.common.sas.AccountSasPermission import com.azure.storage.common.sas.AccountSasResourceType import com.azure.storage.common.sas.AccountSasService @@ -35,6 +37,8 @@ import com.azure.storage.common.sas.AccountSasSignatureValues import groovy.transform.CompileStatic import groovy.transform.Memoized import groovy.util.logging.Slf4j +import nextflow.cloud.azure.config.AzConfig +import nextflow.cloud.azure.config.AzRetryConfig import nextflow.cloud.azure.nio.AzPath import nextflow.util.Duration /** @@ -180,6 +184,7 @@ class AzHelper { return new BlobServiceClientBuilder() .endpoint(endpoint) .credential(credential) + .retryOptions(requestRetryOptions()) .buildClient() } @@ -197,6 +202,7 @@ class AzHelper { return new BlobServiceClientBuilder() .endpoint(endpoint) .sasToken(sasToken) + .retryOptions(requestRetryOptions()) .buildClient() } @@ -215,6 +221,7 @@ class AzHelper { return new BlobServiceClientBuilder() .credential(credential) .endpoint(endpoint) + .retryOptions(requestRetryOptions()) .buildClient() } @@ -231,7 +238,26 @@ class AzHelper { return new BlobServiceClientBuilder() .credential(credentialBuilder.build()) .endpoint(endpoint) + .retryOptions(requestRetryOptions()) .buildClient() } + @Memoized + static protected RequestRetryOptions requestRetryOptions() { + final cfg = AzConfig.getConfig().retryConfig() + return requestRetryOptions0(cfg) + } + + static protected RequestRetryOptions requestRetryOptions0(AzRetryConfig cfg) { + final retryDelay = java.time.Duration.ofMillis(cfg.getDelay().millis) + final maxRetryDelay = java.time.Duration.ofMillis(cfg.getMaxDelay().millis) + new RequestRetryOptions( + RetryPolicyType.EXPONENTIAL, + cfg.maxAttempts, + null, + retryDelay, + maxRetryDelay, + null) + } + } diff --git a/plugins/nf-azure/src/test/nextflow/cloud/azure/batch/AzHelperTest.groovy b/plugins/nf-azure/src/test/nextflow/cloud/azure/batch/AzHelperTest.groovy new file mode 100644 index 0000000000..c1c2fd342a --- /dev/null +++ b/plugins/nf-azure/src/test/nextflow/cloud/azure/batch/AzHelperTest.groovy @@ -0,0 +1,52 @@ +/* + * Copyright 2013-2024, Seqera Labs + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package nextflow.cloud.azure.batch + +import java.time.Duration + +import com.azure.storage.common.policy.RetryPolicyType +import nextflow.cloud.azure.config.AzRetryConfig +import spock.lang.Specification +import spock.lang.Unroll + +/** + * + * @author Paolo Di Tommaso + */ +class AzHelperTest extends Specification { + + @Unroll + def 'should create retry options' () { + given: + def opts = AzHelper.requestRetryOptions0(CONFIG) + expect: + opts.@retryPolicyType == RetryPolicyType.EXPONENTIAL + opts.maxRetryDelay.toMillis() == CONFIG.maxDelay.millis + opts.retryDelay.toMillis() == CONFIG.delay.millis + opts.maxTries == CONFIG.maxAttempts + and: + opts.secondaryHost == null + opts.tryTimeoutDuration == Duration.ofSeconds(Integer.MAX_VALUE) + + where: + _ | CONFIG + _ | new AzRetryConfig() + _ | new AzRetryConfig([delay: '10s', maxAttempts: 20, maxDelay: '200s']) + } + +}