Skip to content

Conversation

@bedrin
Copy link

@bedrin bedrin commented Oct 31, 2025

No description provided.

paulbakker and others added 11 commits October 21, 2025 15:21
Signed-off-by: Paul Bakker <[email protected]>
…spring-boot-4-preparations-joined-efforts

# Conflicts:
#	auto-configurations/common/spring-ai-autoconfigure-retry/src/main/java/org/springframework/ai/retry/autoconfigure/SpringAiRetryAutoConfiguration.java
#	auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webflux/src/test/java/org/springframework/ai/mcp/server/autoconfigure/McpServerSseWebFluxAutoConfigurationTests.java
#	auto-configurations/models/chat/memory/repository/spring-ai-autoconfigure-model-chat-memory-repository-cassandra/src/main/java/org/springframework/ai/model/chat/memory/repository/cassandra/autoconfigure/CassandraChatMemoryRepositoryAutoConfiguration.java
#	auto-configurations/models/chat/memory/repository/spring-ai-autoconfigure-model-chat-memory-repository-jdbc/src/main/java/org/springframework/ai/model/chat/memory/repository/jdbc/autoconfigure/JdbcChatMemoryRepositoryAutoConfiguration.java
#	auto-configurations/models/chat/memory/repository/spring-ai-autoconfigure-model-chat-memory-repository-jdbc/src/test/java/org/springframework/ai/model/chat/memory/repository/jdbc/autoconfigure/JdbcChatMemoryRepositoryHsqldbAutoConfigurationIT.java
#	auto-configurations/models/chat/memory/repository/spring-ai-autoconfigure-model-chat-memory-repository-neo4j/src/main/java/org/springframework/ai/model/chat/memory/repository/neo4j/autoconfigure/Neo4jChatMemoryRepositoryAutoConfiguration.java
#	auto-configurations/models/spring-ai-autoconfigure-model-anthropic/pom.xml
#	auto-configurations/models/spring-ai-autoconfigure-model-anthropic/src/main/java/org/springframework/ai/model/anthropic/autoconfigure/AnthropicChatAutoConfiguration.java
#	auto-configurations/models/spring-ai-autoconfigure-model-deepseek/pom.xml
#	auto-configurations/models/spring-ai-autoconfigure-model-deepseek/src/main/java/org/springframework/ai/model/deepseek/autoconfigure/DeepSeekChatAutoConfiguration.java
#	auto-configurations/models/spring-ai-autoconfigure-model-elevenlabs/pom.xml
#	auto-configurations/models/spring-ai-autoconfigure-model-elevenlabs/src/main/java/org/springframework/ai/model/elevenlabs/autoconfigure/ElevenLabsAutoConfiguration.java
#	auto-configurations/models/spring-ai-autoconfigure-model-minimax/src/main/java/org/springframework/ai/model/minimax/autoconfigure/MiniMaxChatAutoConfiguration.java
#	auto-configurations/models/spring-ai-autoconfigure-model-minimax/src/main/java/org/springframework/ai/model/minimax/autoconfigure/MiniMaxEmbeddingAutoConfiguration.java
#	auto-configurations/models/spring-ai-autoconfigure-model-mistral-ai/src/main/java/org/springframework/ai/model/mistralai/autoconfigure/MistralAiChatAutoConfiguration.java
#	auto-configurations/models/spring-ai-autoconfigure-model-mistral-ai/src/main/java/org/springframework/ai/model/mistralai/autoconfigure/MistralAiEmbeddingAutoConfiguration.java
#	auto-configurations/models/spring-ai-autoconfigure-model-mistral-ai/src/main/java/org/springframework/ai/model/mistralai/autoconfigure/MistralAiModerationAutoConfiguration.java
#	auto-configurations/models/spring-ai-autoconfigure-model-mistral-ai/src/main/java/org/springframework/ai/model/mistralai/autoconfigure/MistralAiOcrAutoConfiguration.java
#	auto-configurations/models/spring-ai-autoconfigure-model-ollama/src/test/java/org/springframework/ai/model/ollama/autoconfigure/BaseOllamaIT.java
#	auto-configurations/models/spring-ai-autoconfigure-model-openai/src/main/java/org/springframework/ai/model/openai/autoconfigure/OpenAiAudioSpeechAutoConfiguration.java
#	auto-configurations/models/spring-ai-autoconfigure-model-openai/src/main/java/org/springframework/ai/model/openai/autoconfigure/OpenAiAudioTranscriptionAutoConfiguration.java
#	auto-configurations/models/spring-ai-autoconfigure-model-openai/src/main/java/org/springframework/ai/model/openai/autoconfigure/OpenAiChatAutoConfiguration.java
#	auto-configurations/models/spring-ai-autoconfigure-model-openai/src/main/java/org/springframework/ai/model/openai/autoconfigure/OpenAiEmbeddingAutoConfiguration.java
#	auto-configurations/models/spring-ai-autoconfigure-model-openai/src/main/java/org/springframework/ai/model/openai/autoconfigure/OpenAiImageAutoConfiguration.java
#	auto-configurations/models/spring-ai-autoconfigure-model-openai/src/main/java/org/springframework/ai/model/openai/autoconfigure/OpenAiModerationAutoConfiguration.java
#	auto-configurations/models/spring-ai-autoconfigure-model-openai/src/test/java/org/springframework/ai/model/openai/autoconfigure/OpenAiAutoConfigurationIT.java
#	auto-configurations/models/spring-ai-autoconfigure-model-openai/src/test/java/org/springframework/ai/model/openai/autoconfigure/OpenAiModelConfigurationTests.java
#	auto-configurations/models/spring-ai-autoconfigure-model-openai/src/test/java/org/springframework/ai/model/openai/autoconfigure/OpenAiPropertiesTests.java
#	auto-configurations/models/spring-ai-autoconfigure-model-openai/src/test/java/org/springframework/ai/model/openai/autoconfigure/OpenAiResponseFormatPropertiesTests.java
#	auto-configurations/models/spring-ai-autoconfigure-model-postgresml-embedding/src/main/java/org/springframework/ai/model/postgresml/autoconfigure/PostgresMlEmbeddingAutoConfiguration.java
#	auto-configurations/models/spring-ai-autoconfigure-model-stability-ai/src/main/java/org/springframework/ai/model/stabilityai/autoconfigure/StabilityAiImageAutoConfiguration.java
#	auto-configurations/models/spring-ai-autoconfigure-model-zhipuai/pom.xml
#	auto-configurations/models/spring-ai-autoconfigure-model-zhipuai/src/main/java/org/springframework/ai/model/zhipuai/autoconfigure/ZhiPuAiChatAutoConfiguration.java
#	auto-configurations/models/spring-ai-autoconfigure-model-zhipuai/src/main/java/org/springframework/ai/model/zhipuai/autoconfigure/ZhiPuAiEmbeddingAutoConfiguration.java
#	auto-configurations/models/spring-ai-autoconfigure-model-zhipuai/src/main/java/org/springframework/ai/model/zhipuai/autoconfigure/ZhiPuAiImageAutoConfiguration.java
#	auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-cassandra/src/main/java/org/springframework/ai/vectorstore/cassandra/autoconfigure/CassandraVectorStoreAutoConfiguration.java
#	auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-couchbase/src/main/java/org/springframework/ai/vectorstore/couchbase/autoconfigure/CouchbaseSearchVectorStoreAutoConfiguration.java
#	auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-couchbase/src/test/java/org/springframework/ai/vectorstore/couchbase/autoconfigure/CouchbaseSearchVectorStoreAutoConfigurationIT.java
#	auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-elasticsearch/src/main/java/org/springframework/ai/vectorstore/elasticsearch/autoconfigure/ElasticsearchVectorStoreAutoConfiguration.java
#	auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-elasticsearch/src/test/java/org/springframework/ai/vectorstore/elasticsearch/autoconfigure/ElasticsearchVectorStoreAutoConfigurationIT.java
#	auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-mariadb/src/main/java/org/springframework/ai/vectorstore/mariadb/autoconfigure/MariaDbStoreAutoConfiguration.java
#	auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-mongodb-atlas/src/test/java/org/springframework/ai/vectorstore/mongodb/autoconfigure/MongoDBAtlasVectorStoreAutoConfigurationIT.java
#	auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-neo4j/src/main/java/org/springframework/ai/vectorstore/neo4j/autoconfigure/Neo4jVectorStoreAutoConfiguration.java
#	auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-oracle/src/main/java/org/springframework/ai/vectorstore/oracle/autoconfigure/OracleVectorStoreAutoConfiguration.java
#	auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-pgvector/src/main/java/org/springframework/ai/vectorstore/pgvector/autoconfigure/PgVectorStoreAutoConfiguration.java
#	auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-redis/src/main/java/org/springframework/ai/vectorstore/redis/autoconfigure/RedisVectorStoreAutoConfiguration.java
#	auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-redis/src/test/java/org/springframework/ai/vectorstore/redis/autoconfigure/RedisVectorStoreAutoConfigurationIT.java
#	memory/repository/spring-ai-model-chat-memory-repository-cassandra/src/test/java/org/springframework/ai/chat/memory/repository/cassandra/CassandraChatMemoryRepositoryIT.java
#	models/spring-ai-anthropic/src/main/java/org/springframework/ai/anthropic/api/AnthropicApi.java
#	models/spring-ai-huggingface/pom.xml
#	models/spring-ai-openai/src/main/java/org/springframework/ai/openai/api/OpenAiApi.java
#	models/spring-ai-openai/src/main/java/org/springframework/ai/openai/api/OpenAiFileApi.java
#	models/spring-ai-openai/src/main/java/org/springframework/ai/openai/metadata/support/OpenAiResponseHeaderExtractor.java
#	models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/OpenAiChatModelWithChatResponseMetadataTests.java
#	models/spring-ai-zhipuai/src/main/java/org/springframework/ai/zhipuai/api/ZhiPuAiApi.java
#	pom.xml
#	spring-ai-model/src/test/kotlin/org/springframework/ai/tool/resolution/TypeResolverHelperKotlinIT.kt
#	spring-ai-retry/pom.xml
#	spring-ai-retry/src/main/java/org/springframework/ai/retry/RetryUtils.java
#	spring-ai-spring-boot-docker-compose/src/main/java/org/springframework/ai/docker/compose/service/connection/mongo/MongoDbAtlasLocalDockerComposeConnectionDetailsFactory.java
#	spring-ai-spring-boot-docker-compose/src/test/java/org/springframework/ai/docker/compose/service/connection/mongo/MongoDbAtlasLocalDockerComposeConnectionDetailsFactoryIT.java
#	spring-ai-spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/service/connection/test/AbstractDockerComposeIT.java
#	spring-ai-spring-boot-testcontainers/src/test/java/org/springframework/ai/testcontainers/service/connection/mongo/MongoDbAtlasLocalContainerConnectionDetailsFactoryIT.java
#	vector-stores/spring-ai-cassandra-store/src/test/java/org/springframework/ai/vectorstore/cassandra/CassandraRichSchemaVectorStoreIT.java
#	vector-stores/spring-ai-cassandra-store/src/test/java/org/springframework/ai/vectorstore/cassandra/CassandraVectorStoreIT.java
#	vector-stores/spring-ai-cassandra-store/src/test/java/org/springframework/ai/vectorstore/cassandra/WikiVectorStoreExample.java
#	vector-stores/spring-ai-couchbase-store/src/test/java/org/springframework/ai/vectorstore/CouchbaseSearchVectorStoreIT.java
#	vector-stores/spring-ai-elasticsearch-store/src/test/java/org/springframework/ai/vectorstore/elasticsearch/ElasticsearchVectorStoreIT.java
#	vector-stores/spring-ai-elasticsearch-store/src/test/java/org/springframework/ai/vectorstore/elasticsearch/ElasticsearchVectorStoreObservationIT.java
#	vector-stores/spring-ai-mariadb-store/src/test/java/org/springframework/ai/vectorstore/mariadb/MariaDBStoreCustomNamesIT.java
#	vector-stores/spring-ai-mariadb-store/src/test/java/org/springframework/ai/vectorstore/mariadb/MariaDBStoreIT.java
#	vector-stores/spring-ai-mariadb-store/src/test/java/org/springframework/ai/vectorstore/mariadb/MariaDBStoreObservationIT.java
#	vector-stores/spring-ai-milvus-store/src/test/java/org/springframework/ai/vectorstore/milvus/MilvusVectorStoreCustomFieldNamesIT.java
#	vector-stores/spring-ai-milvus-store/src/test/java/org/springframework/ai/vectorstore/milvus/MilvusVectorStoreIT.java
#	vector-stores/spring-ai-neo4j-store/src/test/java/org/springframework/ai/vectorstore/neo4j/Neo4jVectorStoreIT.java
#	vector-stores/spring-ai-neo4j-store/src/test/java/org/springframework/ai/vectorstore/neo4j/Neo4jVectorStoreObservationIT.java
#	vector-stores/spring-ai-opensearch-store/src/test/java/org/springframework/ai/vectorstore/opensearch/OpenSearchVectorStoreIT.java
#	vector-stores/spring-ai-opensearch-store/src/test/java/org/springframework/ai/vectorstore/opensearch/OpenSearchVectorStoreObservationIT.java
#	vector-stores/spring-ai-oracle-store/src/test/java/org/springframework/ai/vectorstore/oracle/OracleVectorStoreIT.java
#	vector-stores/spring-ai-oracle-store/src/test/java/org/springframework/ai/vectorstore/oracle/OracleVectorStoreObservationIT.java
#	vector-stores/spring-ai-pgvector-store/src/test/java/org/springframework/ai/vectorstore/pgvector/PgVectorStoreAutoTruncationIT.java
#	vector-stores/spring-ai-pgvector-store/src/test/java/org/springframework/ai/vectorstore/pgvector/PgVectorStoreCustomNamesIT.java
#	vector-stores/spring-ai-pgvector-store/src/test/java/org/springframework/ai/vectorstore/pgvector/PgVectorStoreIT.java
#	vector-stores/spring-ai-pgvector-store/src/test/java/org/springframework/ai/vectorstore/pgvector/PgVectorStoreObservationIT.java
#	vector-stores/spring-ai-redis-store/src/test/java/org/springframework/ai/vectorstore/redis/RedisVectorStoreIT.java
#	vector-stores/spring-ai-redis-store/src/test/java/org/springframework/ai/vectorstore/redis/RedisVectorStoreObservationIT.java
#	vector-stores/spring-ai-typesense-store/src/test/java/org/springframework/ai/vectorstore/typesense/TypesenseVectorStoreIT.java
Signed-off-by: Dmitry Bedrin <[email protected]>
Signed-off-by: Dmitry Bedrin <[email protected]>
Signed-off-by: Dmitry Bedrin <[email protected]>
Signed-off-by: Dmitry Bedrin <[email protected]>
Signed-off-by: Dmitry Bedrin <[email protected]>
Signed-off-by: Dmitry Bedrin <[email protected]>
Signed-off-by: Dmitry Bedrin <[email protected]>
@bedrin bedrin requested a review from Copilot October 31, 2025 11:19
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR migrates from Spring Retry library to Spring Framework 7's built-in retry functionality. The changes remove the external spring-retry dependency and update all retry-related code to use the new Spring Framework core retry APIs.

Key changes:

  • Removed spring-retry dependency and migrated to org.springframework.core.retry package
  • Updated RetryTemplate instantiation from builder pattern to constructor-based with RetryPolicy
  • Changed RetryListener callback methods to match new API (beforeRetry, onRetrySuccess, onRetryFailure)
  • Replaced MultiValueMap<String, String> with HttpHeaders for API header management
  • Added try-catch blocks to handle RetryException in retry template execute calls

Reviewed Changes

Copilot reviewed 145 out of 145 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
spring-ai-retry/pom.xml Removed spring-retry dependency
spring-ai-retry/src/main/java/org/springframework/ai/retry/*.java Updated retry classes to use Spring Framework 7 core retry APIs
models//src/main/java/**/.java Updated model classes to use new RetryTemplate API and handle RetryException
models/*/src/test/java/**/*Tests.java Updated test retry listeners to use new callback methods
auto-configurations/**/pom.xml Added Spring Boot starter dependencies for JDBC, Redis, MongoDB, etc.
Various API classes Replaced MultiValueMap with HttpHeaders for better type safety
Comments suppressed due to low confidence (1)

models/spring-ai-google-genai/src/main/java/org/springframework/ai/google/genai/GoogleGenAiChatModel.java:682


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +107 to +129
private static RetryTemplate createDefaultRetryTemplate() {
RetryPolicy retryPolicy = RetryPolicy.builder()
.maxAttempts(DEFAULT_MAX_ATTEMPTS)
.includes(TransientAiException.class)
.includes(ResourceAccessException.class)
.delay(Duration.ofMillis(DEFAULT_INITIAL_INTERVAL))
.multiplier(DEFAULT_MULTIPLIER)
.maxDelay(Duration.ofMillis(DEFAULT_MAX_INTERVAL))
.build();

RetryTemplate retryTemplate = new RetryTemplate(retryPolicy);
retryTemplate.setRetryListener(new RetryListener() {
private final AtomicInteger retryCount = new AtomicInteger(0);

@Override
public <T extends Object, E extends Throwable> void onError(RetryContext context,
RetryCallback<T, E> callback, Throwable throwable) {
logger.warn("Retry error. Retry count:{}", context.getRetryCount(), throwable);
public void onRetryFailure(final RetryPolicy policy, final Retryable<?> retryable,
final Throwable throwable) {
int currentRetries = this.retryCount.incrementAndGet();
LOGGER.warn("Retry error. Retry count:{}", currentRetries, throwable);
}
})
.build();
});
return retryTemplate;
}
Copy link

Copilot AI Oct 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The AtomicInteger retryCount in the RetryListener is instance-specific but the RetryTemplate is static and shared. This counter will accumulate across all retry operations globally, not per retry operation. Consider using RetryContext or removing the counter if the new API provides retry count differently.

Copilot uses AI. Check for mistakes.
Comment on lines +136 to +156
private static RetryTemplate createShortRetryTemplate() {
RetryPolicy retryPolicy = RetryPolicy.builder()
.maxAttempts(DEFAULT_MAX_ATTEMPTS)
.includes(TransientAiException.class)
.includes(ResourceAccessException.class)
.delay(Duration.ofMillis(SHORT_INITIAL_INTERVAL))
.build();

RetryTemplate retryTemplate = new RetryTemplate(retryPolicy);
retryTemplate.setRetryListener(new RetryListener() {
private final AtomicInteger retryCount = new AtomicInteger(0);

@Override
public <T extends Object, E extends Throwable> void onError(RetryContext context,
RetryCallback<T, E> callback, Throwable throwable) {
logger.warn("Retry error. Retry count:{}", context.getRetryCount());
public void onRetryFailure(final RetryPolicy policy, final Retryable<?> retryable,
final Throwable throwable) {
int currentRetries = this.retryCount.incrementAndGet();
LOGGER.warn("Retry error. Retry count:{}", currentRetries, throwable);
}
})
.build();
});
return retryTemplate;
}
Copy link

Copilot AI Oct 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same issue as createDefaultRetryTemplate - the AtomicInteger retryCount will accumulate globally across all retry operations since SHORT_RETRY_TEMPLATE is a shared static field.

Copilot uses AI. Check for mistakes.
Comment on lines +419 to +430
catch (RetryException e) {
if (e.getCause() instanceof RuntimeException r) {
throw r;
}

List<Generation> generations = generateContentResponse.getCandidatesList()
.stream()
.map(this::responseCandidateToGeneration)
.flatMap(List::stream)
.toList();

GenerateContentResponse.UsageMetadata usage = generateContentResponse.getUsageMetadata();
Usage currentUsage = (usage != null)
? new DefaultUsage(usage.getPromptTokenCount(), usage.getCandidatesTokenCount())
: new EmptyUsage();
Usage cumulativeUsage = UsageCalculator.getCumulativeUsage(currentUsage, previousChatResponse);
ChatResponse chatResponse = new ChatResponse(generations, toChatResponseMetadata(cumulativeUsage));

observationContext.setResponse(chatResponse);
return chatResponse;
}));
if (e.getCause() instanceof RuntimeException r) {
throw r;
}
else {
throw new RuntimeException(e.getCause());
}
}
Copy link

Copilot AI Oct 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplicate conditional check - the first if (e.getCause() instanceof RuntimeException r) block is redundant and unreachable code follows it.

Copilot uses AI. Check for mistakes.
Signed-off-by: Dmitry Bedrin <[email protected]>
Signed-off-by: Dmitry Bedrin <[email protected]>
}
}

AnthropicApi.ChatCompletionResponse completionResponse = completionEntity.getBody();
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it the same behaviour as it was previously?
If yes, we need to make sure that we're handling RetryException's in all places where we use RetryTemplate

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This mimics the old behavior, only if the cause is not a RuntimeException, the behavior would technically be different.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@bedrin bedrin changed the base branch from feature/spring-boot-4-support to feature/spring-boot-4-preparations October 31, 2025 13:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants