smallrye / smallrye-graphql

Implementation for MicroProfile GraphQL
Apache License 2.0
160 stars 92 forks source link

Fix ConcurrentModificationException in federation fetcher #2186

Closed RoMiRoSSaN closed 2 months ago

RoMiRoSSaN commented 2 months ago

@jmartisk, Hi. When testing federation with many parallel requests (aliased queries, many different), I caught an error. It occurs only on the first call and only if the router sends many parallel requests.

ERROR [io.sma.graphql] (vert.x-eventloop-thread-0) SRGQL012000: Data Fetching Error: java.util.ConcurrentModificationException
    at java.base/java.util.HashMap.computeIfAbsent(HashMap.java:1229)
    at io.smallrye.graphql.bootstrap.FederationDataFetcher.lambda$get$4(FederationDataFetcher.java:61)
    at java.base/java.util.stream.Collectors.lambda$uniqKeysMapAccumulator$1(Collectors.java:180)
    at java.base/java.util.stream.ReduceOps$3ReducingSink.accept(ReduceOps.java:169)
    at java.base/java.util.HashMap$KeySpliterator.forEachRemaining(HashMap.java:1715)
    at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
    at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
    at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:921)
    at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
    at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:682)
    at io.smallrye.graphql.bootstrap.FederationDataFetcher.get(FederationDataFetcher.java:61)
    at io.smallrye.graphql.bootstrap.FederationDataFetcher.get(FederationDataFetcher.java:37)
    at graphql.execution.ExecutionStrategy.invokeDataFetcher(ExecutionStrategy.java:533)
    at graphql.execution.ExecutionStrategy.fetchField(ExecutionStrategy.java:497)
    at graphql.execution.ExecutionStrategy.fetchField(ExecutionStrategy.java:438)
    at graphql.execution.ExecutionStrategy.resolveFieldWithInfo(ExecutionStrategy.java:397)
    at graphql.execution.ExecutionStrategy.getAsyncFieldValueInfo(ExecutionStrategy.java:335)
    at graphql.execution.AsyncExecutionStrategy.execute(AsyncExecutionStrategy.java:57)
    at graphql.execution.Execution.executeOperation(Execution.java:180)
    at graphql.execution.Execution.execute(Execution.java:116)
    at graphql.GraphQL.execute(GraphQL.java:546)
    at graphql.GraphQL.lambda$parseValidateAndExecute$13(GraphQL.java:476)
    at java.base/java.util.concurrent.CompletableFuture.uniComposeStage(CompletableFuture.java:1187)
    at java.base/java.util.concurrent.CompletableFuture.thenCompose(CompletableFuture.java:2341)
    at graphql.GraphQL.parseValidateAndExecute(GraphQL.java:471)
    at graphql.GraphQL.lambda$executeAsync$9(GraphQL.java:429)
    at java.base/java.util.concurrent.CompletableFuture.uniComposeStage(CompletableFuture.java:1187)
    at java.base/java.util.concurrent.CompletableFuture.thenCompose(CompletableFuture.java:2341)
    at graphql.GraphQL.executeAsync(GraphQL.java:418)
    at io.smallrye.graphql.execution.ExecutionService.lambda$writeAsync$0(ExecutionService.java:235)
    at io.smallrye.context.impl.wrappers.SlowContextualSupplier.get(SlowContextualSupplier.java:21)

Quick fix. With ConcurentHashMap its ok