[BUG]App Configuration pull refresh runs synchronously on the servlet request thread (Mono.just(refreshStores())); a slow or unavailable store blocks user requests

Abierto
#51,215 1 comentario 2 reacciones 0 asignados Ver en GitHub

Los mantenedores suelen responder en 1 día

Nadie ha tomado este issue todavía.

Evaluación

Dificultad
4/5
Tiempo estimado
3-5 días
Aptitud para principiantes
57/100
Tipo de issue
Error
Claridad
Bien especificado
Estado de actividad
Activo
Stack tecnológico
java, spring-boot

Línea de trabajo

Start by reading AppConfigurationEventListener and AppConfigurationPullRefresh.refreshConfigurations() in the App Configuration config modules; the issue identifies the eager Mono.just(refreshStores()) call and the servlet event that triggers it. Trace the existing refresh tests and how they invoke store calls. Done means refresh checks no longer hold servlet request threads during slow store calls, with coverage showing the request can complete independently.

Escrito por el modelo de indexación a partir del texto del issue.

Descripción

needs-triage

With spring-cloud-azure-appconfiguration-config-web on the classpath and monitoring.enabled: true,
AppConfigurationEventListener handles every ServletRequestHandledEvent by calling
appConfigurationRefresh.refreshConfigurations().subscribe().

AppConfigurationPullRefresh.refreshConfigurations() is implemented as:

public Mono<Boolean> refreshConfigurations() {
    return Mono.just(refreshStores());
}

Mono.just(...) evaluates its argument eagerly, so refreshStores() (which makes blocking HTTP calls to the
store) runs synchronously on the Tomcat request thread before .subscribe() is reached.
ServletRequestHandledEvent is published inside FrameworkServlet.processRequest before the response is
completed, so the client waits for the refresh too.

When the store is slow or unavailable, whichever user request happens to trigger the refresh check is held for
the full duration of the store call (up to the HTTP client's 60 s response timeout).

This looks like the same issue as #37018 (reported against 5.x). That issue was closed as stale, with a note that
v6 should fix it and to open a new issue if it didn't. It is still present in 7.4.0.

Versions

  • spring-cloud-azure-appconfiguration-config(-web): observed on 7.0.0, same code in 7.4.0 (latest)
  • Spring Boot 3.x, servlet stack (Tomcat), Java 21

Observed in production

  • Normal: refresh check median ~20 ms, so the cost is invisible.
  • Store returned HTTP 503 for ~40 min: each refresh check took 5–15 s (some 60 s). User-facing requests that
    triggered the check took 18–32 s instead of milliseconds, even though the controller had already finished.
  • One case: the controller completed in ~33 ms and the response was sent after ~61 s (refresh timed out after 60 s).

To Reproduce

  1. Spring Boot servlet app with spring-cloud-azure-starter-appconfiguration-config, monitoring enabled:
    spring.cloud.azure.appconfiguration.stores[0]:
      endpoint: https://<store>.azconfig.io
      monitoring:
        enabled: true
        refresh-interval: 30s
        triggers:
          - key: sentinel
    
  2. Start the app, then make the store unreachable (e.g. drop outbound traffic to the store's IP, or point the hostname at a non-routable address).
  3. Wait >30 s, then call any endpoint (GET /anything).
  4. The response takes as long as the store call times out (~60 s), although the handler returned immediately.

Expected behavior
The refresh check must not block request threads. Either make the call actually asynchronous
(Mono.fromCallable(this::refreshStores).subscribeOn(Schedulers.boundedElastic()), or dispatch to an executor),
or run the check from a scheduler rather than from ServletRequestHandledEvent. A short, configurable timeout for
refresh calls would also help.

Lenguaje dominante
Java
Estrellas
2.6k
Forks
2.2k
Merge medio
1 d 17 h
PR fusionados (30 d)
259

Preparar el entorno

Abrir en Codespaces

Inicia el contenedor de desarrollo del proyecto en tu navegador, con tu propia cuenta de GitHub.

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Más de Azure/azure-sdk-for-java

Todos los issues de Azure/azure-sdk-for-java

Issues similares

Más issues de Java

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.