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

Aperta
#51,215 1 commento 2 reazioni 0 assegnatari Vedi su GitHub

I maintainer di solito rispondono entro 1 giorno

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
4/5
Tempo stimato
3-5 giorni
Idoneità per principianti
57/100
Tipo di issue
Bug
Chiarezza
Specificata chiaramente
Stato di attività
Attiva
Stack tecnologico
java, spring-boot

Direzione di ricerca

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.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

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.

Lingua principale
Java
Stelle
2.6k
Fork
2.2k
Merge medio
1g 17h
PR unite (30g)
259

Preparare l'ambiente

Apri in Codespaces

Avvia il container di sviluppo del progetto nel browser, con il tuo account GitHub.

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di Azure/azure-sdk-for-java

Tutte le issue di Azure/azure-sdk-for-java

Issue simili

Altre issue su Java

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.