Skip to content

Commit ee57b69

Browse files
authored
Fix incorrect query intermittent results due to result list proxies (#379)
* Fix incorrect query intermittent results due to result list proxies * remove legacy batch loader registry context * make query result list streams and batch loaders thread safe * Remove transactional from GraphQLController * Auto-configure shared entity manager for graphql schema builder instance
1 parent f7fbd31 commit ee57b69

File tree

16 files changed

+206
-204
lines changed

16 files changed

+206
-204
lines changed

.github/workflows/build.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@ name: CI
33
on:
44
workflow_dispatch:
55
push:
6-
branches: [ "master" ]
6+
branches: [ "0.5.x" ]
77
paths-ignore:
88
- '**/README.md'
99
pull_request:
10-
branches: [ "master" ]
10+
branches: [ "0.5.x" ]
1111
paths-ignore:
1212
- '**/README.md'
1313

graphql-jpa-query-autoconfigure/pom.xml

+4
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@
3232
<groupId>org.springframework.boot</groupId>
3333
<artifactId>spring-boot-autoconfigure</artifactId>
3434
</dependency>
35+
<dependency>
36+
<groupId>org.springframework</groupId>
37+
<artifactId>spring-orm</artifactId>
38+
</dependency>
3539
<dependency>
3640
<groupId>javax.validation</groupId>
3741
<artifactId>validation-api</artifactId>
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
package com.introproventures.graphql.jpa.query.autoconfigure;
22

33
import graphql.GraphQL;
4-
import org.dataloader.DataLoaderOptions;
5-
import org.dataloader.MappedBatchLoaderWithContext;
6-
import org.springframework.beans.factory.InitializingBean;
74
import org.springframework.beans.factory.ListableBeanFactory;
85
import org.springframework.boot.autoconfigure.AutoConfiguration;
96
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
@@ -13,9 +10,6 @@
1310
import org.springframework.graphql.ExecutionGraphQlService;
1411
import org.springframework.graphql.execution.BatchLoaderRegistry;
1512
import org.springframework.graphql.execution.GraphQlSource;
16-
import reactor.core.publisher.Mono;
17-
18-
import static com.introproventures.graphql.jpa.query.schema.impl.BatchLoaderRegistry.newDataLoaderRegistry;
1913

2014
@AutoConfiguration(after = GraphQlAutoConfiguration.class)
2115
@ConditionalOnClass({GraphQL.class, GraphQlSource.class})
@@ -35,20 +29,4 @@ ExecutionGraphQlService executionGraphQlService(ListableBeanFactory beanFactory,
3529
return new GraphQlAutoConfiguration(beanFactory).executionGraphQlService(graphQlSource,
3630
batchLoaderRegistry);
3731
}
38-
39-
@Bean
40-
InitializingBean batchLoaderRegistryConfigurer(BatchLoaderRegistry batchLoaderRegistry) {
41-
return () -> {
42-
DataLoaderOptions options = DataLoaderOptions.newOptions()
43-
.setCachingEnabled(false);
44-
newDataLoaderRegistry(options)
45-
.getDataLoadersMap()
46-
.entrySet()
47-
.stream()
48-
.forEach(entry -> batchLoaderRegistry.forName(entry.getKey())
49-
.withOptions(options)
50-
.registerMappedBatchLoader((keys, env) ->
51-
Mono.fromCompletionStage(((MappedBatchLoaderWithContext) entry.getValue()).load(keys, env))));
52-
};
53-
}
5432
}

graphql-jpa-query-autoconfigure/src/main/java/com/introproventures/graphql/jpa/query/autoconfigure/GraphQLSchemaBuilderAutoConfiguration.java

+5-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
package com.introproventures.graphql.jpa.query.autoconfigure;
22

3-
import javax.persistence.EntityManagerFactory;
43
import com.introproventures.graphql.jpa.query.schema.GraphQLSchemaBuilder;
54
import com.introproventures.graphql.jpa.query.schema.RestrictedKeysProvider;
65
import com.introproventures.graphql.jpa.query.schema.impl.GraphQLJpaSchemaBuilder;
76
import graphql.GraphQL;
7+
import javax.persistence.EntityManager;
8+
import javax.persistence.EntityManagerFactory;
89
import org.springframework.beans.factory.ObjectProvider;
910
import org.springframework.boot.autoconfigure.AutoConfiguration;
1011
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
@@ -13,6 +14,7 @@
1314
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
1415
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
1516
import org.springframework.context.annotation.Bean;
17+
import org.springframework.orm.jpa.SharedEntityManagerCreator;
1618

1719
@AutoConfiguration(
1820
before = {GraphQLSchemaAutoConfiguration.class, GraphQLJpaQueryGraphQlSourceAutoConfiguration.class},
@@ -28,7 +30,8 @@ public class GraphQLSchemaBuilderAutoConfiguration {
2830
GraphQLJpaSchemaBuilder defaultGraphQLJpaSchemaBuilder(EntityManagerFactory entityManagerFactory,
2931
GraphQLJpaQueryProperties properties,
3032
ObjectProvider<RestrictedKeysProvider> restrictedKeysProvider) {
31-
GraphQLJpaSchemaBuilder builder = new GraphQLJpaSchemaBuilder(entityManagerFactory.createEntityManager());
33+
EntityManager entityManager = SharedEntityManagerCreator.createSharedEntityManager(entityManagerFactory);
34+
GraphQLJpaSchemaBuilder builder = new GraphQLJpaSchemaBuilder(entityManager);
3235

3336
builder.name(properties.getName())
3437
.description(properties.getDescription())

graphql-jpa-query-autoconfigure/src/test/java/com/introproventures/graphql/jpa/query/autoconfigure/GraphQLSchemaAutoConfigurationTest.java

+24-26
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,15 @@
11
package com.introproventures.graphql.jpa.query.autoconfigure;
22

3-
import java.io.File;
4-
import java.io.IOException;
5-
import java.time.Duration;
6-
import java.time.Instant;
7-
import java.util.LinkedHashMap;
8-
import java.util.List;
9-
import java.util.Map;
10-
import java.util.Set;
11-
import java.util.UUID;
12-
import java.util.function.Supplier;
13-
import java.util.stream.Collectors;
14-
import java.util.stream.Stream;
3+
import static graphql.annotations.AnnotationsSchemaCreator.newAnnotationsSchema;
4+
import static graphql.schema.FieldCoordinates.coordinates;
5+
import static graphql.schema.GraphQLCodeRegistry.newCodeRegistry;
6+
import static graphql.schema.GraphQLFieldDefinition.newFieldDefinition;
7+
import static graphql.schema.GraphQLObjectType.newObject;
8+
import static graphql.schema.GraphQLSchema.newSchema;
9+
import static graphql.schema.idl.RuntimeWiring.newRuntimeWiring;
10+
import static java.util.Collections.emptyMap;
11+
import static org.assertj.core.api.Assertions.assertThat;
12+
1513
import com.introproventures.graphql.jpa.query.autoconfigure.support.AdditionalGraphQLType;
1614
import com.introproventures.graphql.jpa.query.autoconfigure.support.MutationRoot;
1715
import com.introproventures.graphql.jpa.query.autoconfigure.support.QueryRoot;
@@ -41,6 +39,18 @@
4139
import graphql.schema.idl.SchemaGenerator;
4240
import graphql.schema.idl.SchemaParser;
4341
import graphql.schema.idl.TypeDefinitionRegistry;
42+
import java.io.File;
43+
import java.io.IOException;
44+
import java.time.Duration;
45+
import java.time.Instant;
46+
import java.util.LinkedHashMap;
47+
import java.util.List;
48+
import java.util.Map;
49+
import java.util.Set;
50+
import java.util.UUID;
51+
import java.util.function.Supplier;
52+
import java.util.stream.Collectors;
53+
import java.util.stream.Stream;
4454
import org.junit.Test;
4555
import org.junit.runner.RunWith;
4656
import org.reactivestreams.Publisher;
@@ -58,16 +68,6 @@
5868
import reactor.core.publisher.Flux;
5969
import reactor.test.StepVerifier;
6070

61-
import static graphql.annotations.AnnotationsSchemaCreator.newAnnotationsSchema;
62-
import static graphql.schema.FieldCoordinates.coordinates;
63-
import static graphql.schema.GraphQLCodeRegistry.newCodeRegistry;
64-
import static graphql.schema.GraphQLFieldDefinition.newFieldDefinition;
65-
import static graphql.schema.GraphQLObjectType.newObject;
66-
import static graphql.schema.GraphQLSchema.newSchema;
67-
import static graphql.schema.idl.RuntimeWiring.newRuntimeWiring;
68-
import static java.util.Collections.emptyMap;
69-
import static org.assertj.core.api.Assertions.assertThat;
70-
7171
@RunWith(SpringRunner.class)
7272
@SpringBootTest(webEnvironment=WebEnvironment.NONE)
7373
public class GraphQLSchemaAutoConfigurationTest {
@@ -77,11 +77,11 @@ public class GraphQLSchemaAutoConfigurationTest {
7777

7878
@Autowired
7979
private GraphQLJpaQueryProperties graphQLJpaQueryProperties;
80-
80+
8181
@SpringBootApplication
8282
@EnableGraphQLJpaQuerySchema(basePackageClasses = TestEntity.class)
8383
static class Application {
84-
84+
8585
@Configuration
8686
static class GraphQLAnnotationsSchemaConfigurer implements GraphQLSchemaConfigurer {
8787
@Autowired(required = false)
@@ -383,6 +383,4 @@ public void defaultConfigurationProperties() {
383383
assertThat(graphQLJpaQueryProperties.isUseDistinctParameter()).isFalse();
384384
assertThat(graphQLJpaQueryProperties.isToManyDefaultOptional()).isTrue();
385385
}
386-
387-
388386
}

graphql-jpa-query-boot-starter-graphql/src/test/java/com/introproventures/graphql/jpa/query/boot/test/boot/autoconfigure/GraphQLJpaQueryGraphQlSourceAutoConfigurationTest.java

+3-12
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,15 @@
1515
*/
1616
package com.introproventures.graphql.jpa.query.boot.test.boot.autoconfigure;
1717

18+
import static org.assertj.core.api.Assertions.assertThat;
19+
1820
import com.introproventures.graphql.jpa.query.autoconfigure.EnableGraphQLJpaQuerySchema;
1921
import com.introproventures.graphql.jpa.query.autoconfigure.JavaScalarsRuntimeWiringConfigurer;
2022
import com.introproventures.graphql.jpa.query.boot.test.starter.model.Author;
2123
import com.introproventures.graphql.jpa.query.schema.GraphQLSchemaBuilder;
2224
import com.introproventures.graphql.jpa.query.schema.impl.GraphQLJpaSchemaBuilder;
2325
import graphql.schema.GraphQLObjectType;
2426
import graphql.schema.GraphQLSchema;
25-
import org.dataloader.DataLoaderRegistry;
2627
import org.junit.Test;
2728
import org.junit.runner.RunWith;
2829
import org.springframework.beans.factory.annotation.Autowired;
@@ -35,10 +36,6 @@
3536
import org.springframework.graphql.execution.RuntimeWiringConfigurer;
3637
import org.springframework.test.context.junit4.SpringRunner;
3738

38-
import static graphql.GraphQLContext.newContext;
39-
import static org.assertj.core.api.Assertions.assertThat;
40-
import static org.dataloader.DataLoaderRegistry.newRegistry;
41-
4239
@RunWith(SpringRunner.class)
4340
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
4441
public class GraphQLJpaQueryGraphQlSourceAutoConfigurationTest {
@@ -81,11 +78,5 @@ public void contextIsAutoConfigured() {
8178
.extracting(GraphQLObjectType::getName, GraphQLObjectType::getDescription)
8279
.containsExactly("GraphQLBooks", "GraphQL Books Schema Description");
8380

84-
DataLoaderRegistry dataLoaderRegistry = newRegistry().build();
85-
batchLoaderRegistry.registerDataLoaders(dataLoaderRegistry, newContext().build());
86-
87-
assertThat(dataLoaderRegistry.getDataLoadersMap())
88-
.isNotEmpty()
89-
.containsOnlyKeys("Author.books", "Book.author");
9081
}
91-
}
82+
}

graphql-jpa-query-build/pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
<repository>
2121
<id>spring-milestones</id>
2222
<name>Spring Milestones</name>
23-
<url>http://repo.spring.io/milestone</url>
23+
<url>https://repo.spring.io/milestone</url>
2424
<releases>
2525
<enabled>true</enabled>
2626
</releases>

graphql-jpa-query-example-merge/src/main/java/com/introproventures/graphql/jpa/query/example/Application.java

+18-10
Original file line numberDiff line numberDiff line change
@@ -17,25 +17,25 @@
1717

1818
import static graphql.schema.visibility.DefaultGraphqlFieldVisibility.DEFAULT_FIELD_VISIBILITY;
1919

20+
import graphql.GraphQLContext;
21+
import graphql.execution.instrumentation.Instrumentation;
22+
import graphql.execution.instrumentation.SimpleInstrumentation;
23+
import graphql.execution.instrumentation.tracing.TracingInstrumentation;
24+
import graphql.schema.visibility.BlockedFields;
25+
import graphql.schema.visibility.GraphqlFieldVisibility;
2026
import java.util.function.Supplier;
21-
2227
import javax.servlet.http.HttpServletRequest;
23-
2428
import org.slf4j.Logger;
2529
import org.slf4j.LoggerFactory;
2630
import org.springframework.boot.SpringApplication;
2731
import org.springframework.boot.autoconfigure.SpringBootApplication;
2832
import org.springframework.context.annotation.Bean;
33+
import org.springframework.context.annotation.Primary;
34+
import org.springframework.data.transaction.ChainedTransactionManager;
35+
import org.springframework.transaction.PlatformTransactionManager;
2936
import org.springframework.transaction.annotation.EnableTransactionManagement;
3037
import org.springframework.web.context.annotation.RequestScope;
3138

32-
import graphql.GraphQLContext;
33-
import graphql.execution.instrumentation.Instrumentation;
34-
import graphql.execution.instrumentation.SimpleInstrumentation;
35-
import graphql.execution.instrumentation.tracing.TracingInstrumentation;
36-
import graphql.schema.visibility.BlockedFields;
37-
import graphql.schema.visibility.GraphqlFieldVisibility;
38-
3939
/**
4040
* GraphQL JPA Query Example with Spring Boot Autoconfiguration
4141
*
@@ -79,5 +79,13 @@ public Supplier<Instrumentation> instrumentation(HttpServletRequest request) {
7979
? new TracingInstrumentation()
8080
: SimpleInstrumentation.INSTANCE;
8181
}
82-
82+
83+
84+
@Primary
85+
PlatformTransactionManager transactionManager(
86+
PlatformTransactionManager bookTransactionManager,
87+
PlatformTransactionManager starWarsTransactionManager
88+
) {
89+
return new ChainedTransactionManager(bookTransactionManager, starWarsTransactionManager);
90+
}
8391
}

0 commit comments

Comments
 (0)