001/* 002 * Copyright © 2025 CUI-OpenSource-Software (info@cuioss.de) 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package de.cuioss.http.client.retry; 017 018import de.cuioss.http.client.result.HttpResultObject; 019 020import java.util.concurrent.CompletableFuture; 021 022/** 023 * HTTP-specific retry strategy interface using virtual threads and asynchronous execution. 024 * 025 * <h2>Async Design with Virtual Threads</h2> 026 * This interface leverages Java 21's virtual threads to provide efficient, non-blocking retry operations: 027 * 028 * <ul> 029 * <li><strong>Non-blocking delays</strong> - Uses CompletableFuture.delayedExecutor() instead of Thread.sleep()</li> 030 * <li><strong>Virtual thread execution</strong> - Operations run on lightweight virtual threads</li> 031 * <li><strong>Composable operations</strong> - CompletableFuture API enables natural async composition</li> 032 * <li><strong>Resource efficient</strong> - No blocked threads during retry delays</li> 033 * <li><strong>Scalable</strong> - Handles thousands of concurrent retry operations</li> 034 * </ul> 035 * 036 * <h2>Result Pattern Approach</h2> 037 * Continues to use the CUI result pattern with enhanced async capabilities: 038 * 039 * <ul> 040 * <li><strong>No exceptions for flow control</strong> - All error states become result states</li> 041 * <li><strong>Rich error context</strong> - HttpResultObject contains retry metrics, error codes, and details</li> 042 * <li><strong>Forced error handling</strong> - Cannot access result without checking state</li> 043 * <li><strong>Graceful degradation</strong> - Built-in fallback support with default results</li> 044 * <li><strong>State-based flow</strong> - FRESH, CACHED, STALE, RECOVERED, ERROR states</li> 045 * </ul> 046 * 047 * <h2>Usage Patterns</h2> 048 * <h3>Blocking Usage (Legacy Compatibility)</h3> 049 * <pre> 050 * RetryStrategy strategy = RetryStrategies.exponentialBackoff(); 051 * HttpResultObject<String> result = strategy.execute(operation, context).get(); 052 * 053 * if (!result.isValid()) { 054 * // Handle error cases 055 * useFallbackContent(result.getResult()); 056 * } else { 057 * processResult(result.getResult()); 058 * } 059 * </pre> 060 * 061 * <h3>Async Composition (Recommended)</h3> 062 * <pre> 063 * strategy.execute(operation, context) 064 * .thenCompose(result -> { 065 * if (result.isValid()) { 066 * return processResult(result.getResult()); 067 * } else { 068 * return handleError(result); 069 * } 070 * }) 071 * .thenAccept(processed -> updateCache(processed)) 072 * .exceptionally(ex -> handleException(ex)); 073 * </pre> 074 */ 075@FunctionalInterface 076public interface RetryStrategy { 077 078 /** 079 * Executes the given HTTP operation with retry logic using virtual threads and async execution. 080 * 081 * <p>This method runs operations on virtual threads with non-blocking delays between retry attempts. 082 * The implementation uses {@code CompletableFuture.delayedExecutor()} with virtual thread executors 083 * to provide efficient, scalable retry operations without blocking threads during delays.</p> 084 * 085 * @param <T> the type of result returned by the operation 086 * @param operation the HTTP operation to retry 087 * @param context retry context with operation name and attempt info 088 * @return CompletableFuture containing HttpResultObject with result and comprehensive error/retry information 089 */ 090 <T> CompletableFuture<HttpResultObject<T>> execute(HttpOperation<T> operation, RetryContext context); 091 092 /** 093 * Creates a no-op retry strategy (single attempt only). 094 * Useful for disabling retry in specific scenarios or configurations. 095 * 096 * @return a retry strategy that executes the operation exactly once using virtual threads 097 */ 098 static RetryStrategy none() { 099 return new RetryStrategy() { 100 @Override 101 public <T> CompletableFuture<HttpResultObject<T>> execute(HttpOperation<T> operation, RetryContext context) { 102 // No retry - just execute once on virtual thread and return completed future 103 return CompletableFuture.completedFuture(operation.execute()); 104 } 105 }; 106 } 107 108}