[Bug] Memory Leak and Stats Pollution via unmanaged ThreadLocal in ThreadLocalStatisticsCollector
Personne n'a encore pris cette issue.
Évaluation
- Difficulté
- 4/5
- Temps estimé
- 3-5 jours
- Accessibilité débutants
- 35/100
- Type d'issue
- Bug
- Clarté
- À clarifier
- Activité
- Calme
- Stack technique
- java
- Domaine
- backend, observability
Piste de recherche
Commencez par lire ThreadLocalStatisticsCollector, en particulier son utilisation de ThreadLocal, getStatistics() et resetThread(). Exécutez la reproduction fournie avec un fixed-thread-pool afin de vérifier si les statistiques persistent entre les requests lorsque resetThread() est ignoré. Done doit inclure une manière déterminée d’empêcher la pollution et la rétention entre les requests, avec des tests couvrant le scénario reproduit.
Rédigé par le modèle d'indexation à partir du texte de l'issue.
Description
Describe the bug
There is a potential Unintentional ThreadLocal Leak (UTL) in ThreadLocalStatisticsCollector. The class relies on consumers manually calling resetThread() at "request boundaries" to clear the ThreadLocal<SimpleStatisticsCollector>.
However, in typical GraphQL environments (reactive streams, async gateways, or standard thread pools), threads are heavily reused. If an unhandled exception occurs or a developer forgets to call resetThread(), the SimpleStatisticsCollector object is permanently retained by the worker thread.
Impact:
- Data Pollution: Subsequent requests processed by the dirty thread will inherit the accumulated statistics of previous requests, leading to completely distorted metrics.
- Memory Leak (Type I UTL): As more threads in the pool retain these un-cleared statistics objects over time, the heap usage will grow linearly, potentially leading to an
OutOfMemoryErrorin high-throughput applications.
To Reproduce
Here is a simplified code example demonstrating the data pollution in a thread-pool environment when resetThread() is missed (e.g., bypassed due to an exception):
import org.dataloader.stats.ThreadLocalStatisticsCollector;
import java.util.concurrent.*;
public class UTLReproduction {
public static void main(String[] args) throws Exception {
ThreadLocalStatisticsCollector collector = new ThreadLocalStatisticsCollector();
// Simulate a web server with a reusable thread pool
ExecutorService threadPool = Executors.newFixedThreadPool(1);
// Request 1: Execution completes but resetThread() is missed (e.g. exception thrown)
threadPool.submit(() -> {
collector.incrementLoadCount();
// Developer forgets to put collector.resetThread() in a finally block
}).get();
// Request 2: A new incoming request reuses the same dirty thread
threadPool.submit(() -> {
long loadCount = collector.getStatistics().getLoadCount();
// BUG: loadCount is 1 instead of 0! The new request is polluted by Request 1.
System.out.println("New Request Load Count (Expected 0): " + loadCount);
}).get();
threadPool.shutdown();
}
}
- Langage dominant
- Java
- Étoiles
- 525
- Forks
- 102
- Merge moyen
- 2 j 3 h
- PR mergées (30 j)
- 3
Préparer son environnement
Ce projet ne fournit ni conteneur de développement, ni Dockerfile, ni guide de contribution : l'installation est à votre charge. Commencez par son README, et consultez notre guide de la première contribution pour les étapes générales.
Par où commencer
- Lisez l'issue en entier, puis le guide de contribution du projet.
- Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
- Forkez le dépôt et travaillez sur une branche.
- Ouvrez une pull request qui référence le numéro de l'issue.
Autres issues de graphql-java/java-dataloader
-
composing dataloadersOuvertekeep-open
Difficulté 4/5 3-5 jours Accessibilité débutants 30/100
graphql-java/java-dataloader#54 · 22 commentaires · 2 réactions ·
Toutes les issues de graphql-java/java-dataloader
Issues similaires
-
Difficulté 2/5 1-3 heures Accessibilité débutants 72/100
wildfly/wildfly-channel#446 ·
-
Difficulté 2/5 1-3 heures Accessibilité débutants 62/100
Les mainteneurs répondent en général sous 1 jour
-
5.0.x backport enhancement
Difficulté 2/5 1-3 heures Accessibilité débutants 63/100
spring-cloud/spring-cloud-function#1507 ·
Les mainteneurs répondent en général sous 1 jour
-
Difficulté 2/5 1-3 heures Accessibilité débutants 65/100
open-learning-exchange/myplanet#18484 ·
Les mainteneurs répondent en général sous 1 jour
-
ELProcessor.defineFunction() fails for valid method signaturesPeut-être pris @RaphaelFakhri l’a pris aujourd’hui. Ouverte
Difficulté 2/5 1-3 heures Accessibilité débutants 68/100
jakartaee/expression-language#492 ·