Skip to content

Conversation

@Brack93
Copy link

@Brack93 Brack93 commented Dec 12, 2025

Background

Coroutines support for @Cacheable was introduced in 466c8d8 and refined in 6becfe2 (following Spring AOP coroutines support in c8169e5).

While this effectively solves long-lived cache use cases for suspend methods, it does not easily translate to request-scoped caching.

Although there is no direct support for standard methods as well, request-scoped caching is typically achieved by defining a @RequestScope CacheManager bean. However, since @RequestScope mechanism relies on thread local, the same approach is not suitable for coroutines, that can suspend and resume on different threads.

For a coroutine-based WebFlux server, a potential workaround involves explicitly adding to the request coroutine context the required resolved data (or a lazy resolver), using a custom coroutine context element, or manually passing it down the call stack as a method argument. However, this explicit approach strictly ties the implementation of a service - that may need this shared data at a deep request execution level - with the request context. It may also require a huge refactor to pass all the way down the required shared data, if the caching need emerges late in development. Additionally, for Kotlin WebFlux based GraphQL frameworks, clients can batch independent queries within the same request to save network resources, preventing an explicit design on server side that is able to cache common data for each possible queries combination.

For a better separation of concerns, we might prefer instead to inject the data provider as a service dependency, but still avoid duplicated executions within the same request.

Proposal

This PR provides request-scoped, proxy-based, cache management capability to Spring WebFlux servers leveraging Kotlin coroutines.

Specifically, suspend methods of Spring beans can now be annotated with @CoRequestCacheable.

class MyServiceBean {

	@CoRequestCacheable(key = "#userName")
	suspend fun fetchUserAgeFromDownstreamService(userName: String, authHeader: String): Int {
		// prepare request and fetch the user info
		return userInfo.age
	}

}

The cached result is tied to the web request coroutine context, ensuring that each new incoming web request triggers a new execution of the annotated method.

The required infrastructure can be enabled by using @EnableCoRequestCaching on a configuration class.

@Configuration
@EnableCoRequestCaching
class AppConfig {

	@Bean
	fun myService(): MyService {
		// configure and return a class having @CoRequestCacheable suspend methods
		return MyService()
	}

}

Although the proposed implementation could not fit in the already existing @Cacheable infrastructure, individual components have been reused or extended whenever possible to maintain consistency.

This commit provides request-scoped, proxy-based, cache management
capability to Spring WebFlux servers leveraging Kotlin coroutines.

Specifically, suspend methods of Spring beans can now be annotated
with @CoRequestCacheable. The cached result is tied to
the web request coroutine context, so each request will trigger
a new execution of the annotated method.

The required infrastructure can be enabled by using
@EnableCoRequestCaching on a configuration class.

Signed-off-by: Angelo Bracaglia <angelo.bracaglia.ing@gmail.com>
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Dec 12, 2025
@Brack93 Brack93 marked this pull request as ready for review December 12, 2025 02:22
@sdeleuze
Copy link
Contributor

Thanks for this PR, but we prefer to decline it as it is unclear how useful would be such request-scoped caching, as we typically build Coroutines features on top of Reactive ones, and as this kind of @CoRequestCacheable annotation does not seems a good fit in Spring programming model.

@sdeleuze sdeleuze closed this Dec 31, 2025
@sdeleuze sdeleuze added status: declined A suggestion or change that we don't feel we should currently apply theme: kotlin An issue related to Kotlin support and removed status: waiting-for-triage An issue we've not yet triaged or decided on labels Dec 31, 2025
@Brack93
Copy link
Author

Brack93 commented Dec 31, 2025

Thanks for your feedback @sdeleuze.

This PR was inspired by the following kotlin-based open source GraphQL framework, in particular to support something similar to what dataloaders achieve, avoiding duplicated network calls within the same GraphQL request when it includes multiple queries all requiring the same data, but without the need to switch to Futures:

https://opensource.expediagroup.com/graphql-kotlin/docs/server/data-loader/#dataloaders-and-coroutines

Since the above framework is based on Spring Webflux, I thougth it could fit and maybe be useful in general when using Spring WebFlux with Kotlin. Thanks again for the feedback.

@sdeleuze
Copy link
Contributor

Thanks for the additional context and your understanding, I guess my recommendation would be to implement that logic in a programmatic way instead of declarative with annotations. Looks too opinionated for the annotation-based programming model.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

status: declined A suggestion or change that we don't feel we should currently apply theme: kotlin An issue related to Kotlin support

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants