Skip to content

Commit f15b2b7

Browse files
Add performance checks example
1 parent 27bef19 commit f15b2b7

File tree

26 files changed

+1087
-7
lines changed

26 files changed

+1087
-7
lines changed

performance-checks/.gitignore

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
.gradle
2+
/build/
3+
!gradle/wrapper/gradle-wrapper.jar
4+
5+
### STS ###
6+
.apt_generated
7+
.classpath
8+
.factorypath
9+
.project
10+
.settings
11+
.springBeans
12+
.sts4-cache
13+
14+
### IntelliJ IDEA ###
15+
.idea
16+
*.iws
17+
*.iml
18+
*.ipr
19+
/out/
20+
21+
### NetBeans ###
22+
/nbproject/private/
23+
/nbbuild/
24+
/dist/
25+
/nbdist/
26+
/.nb-gradle/

performance-checks/README.md

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
# Performance checks
2+
3+
This example has a few mechanisms to prevent your GraphQL server from dealing with expensive queries sent by abusive clients
4+
(or maybe legitimate clients that running expensive queries unaware of the negative impacts they might cause).
5+
6+
Here we introduce 4 mechanisms to help with that task. 3 of them are based on GraphQL Java instrumentation capabilities,
7+
and the forth one is a bit out GraphQL Java jurisdiction and more related to web servers.
8+
9+
1. MaxQueryDepthInstrumentation: limit the depth of queries to 5
10+
2. MaxQueryComplexityInstrumentation: set complexity values to fields and limit query complexity to 5
11+
3. A custom Instrumentation that sets a timeout period of 3 seconds for DataFetchers
12+
4. A hard request timeout of 10 seconds, specified in the web server level (Spring)
13+
14+
# The schema
15+
The schema we're using is quite simple:
16+
17+
```graphql
18+
type Query {
19+
instrumentedField(sleep: Int): String
20+
characters: [Character]
21+
}
22+
23+
type Character {
24+
name: String!
25+
friends: [Character]
26+
energy: Float
27+
}
28+
```
29+
30+
There are a few interesting facts related to this example.
31+
32+
* instrumentedField: returns a fixed string ("value"). It receives a parameter "sleep" that forces the DataFetcher to
33+
take that amount of seconds to return. Set that value to anything above 3 seconds and a timeout error will be thrown.
34+
This simulates a long running DataFetcher that would be forcefully stopped.
35+
36+
```graphql
37+
{
38+
instrumentedField(sleep: 4) # will result in an error
39+
}
40+
```
41+
42+
* friends: will return a list of characters, that can themselves have friends, and so on... It's quite clear that queries
43+
might overuse this field and end up having a large number of nested friends and characters. Add 5 or more levels of
44+
friends and an error will be thrown.
45+
46+
```graphql
47+
{
48+
characters {
49+
name
50+
friends {
51+
name
52+
friends {
53+
name
54+
friends {
55+
name
56+
friends {
57+
name # an error will be thrown, since the depth is higher than the limit
58+
}
59+
}
60+
}
61+
}
62+
}
63+
}
64+
```
65+
66+
* energy: getting this field involves some expensive calculations, so we've established that it has a complexity value
67+
of 3 (all the other fields have complexity 0). We've also defined that a query can have a maximum complexity of 5. So,
68+
if "energy" is present 2 times or more in a given query, an error will be thrown.
69+
70+
```graphql
71+
{
72+
characters {
73+
name
74+
energy
75+
friends {
76+
name
77+
energy # an error will be thrown, since we've asked for "energy" 2 times
78+
}
79+
}
80+
}
81+
```
82+
83+
# Request timeout
84+
Although this is not really GraphQL Java business, it might be useful to set a hard request timeout on the web server
85+
level.
86+
To achieve this using Spring, the following property can be used:
87+
88+
```
89+
spring.mvc.async.request-timeout=10000
90+
```
91+
92+
93+
# Running the code
94+
95+
To build the example code in this repository type:
96+
97+
```
98+
./gradlew build
99+
```
100+
101+
To run the example code type:
102+
103+
```
104+
./gradlew bootRun
105+
```
106+
107+
To access the example application, point your browser at:
108+
http://localhost:8080/
109+
110+
## Note about introspection and max query depth
111+
A bad side effect of specifying a maximum depth for queries is that this will prevent introspection queries to properly
112+
execute. This affects GraphiQL's documentation and autocomplete features, that will simply not work.
113+
This is a tricky problem to fix and [has been discussed in the past](https://github.com/graphql-java/graphql-java/issues/1055).
114+
115+
You can still use GraphiQL to execute queries and inspect results. If you want documentation and autocomplete back in
116+
GraphiQL, just temporarily disable the max depth instrumentation.

performance-checks/build.gradle

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
buildscript {
2+
ext {
3+
springBootVersion = '2.0.5.RELEASE'
4+
}
5+
repositories {
6+
mavenCentral()
7+
}
8+
dependencies {
9+
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
10+
}
11+
}
12+
13+
apply plugin: 'java'
14+
apply plugin: 'eclipse'
15+
apply plugin: 'org.springframework.boot'
16+
apply plugin: 'io.spring.dependency-management'
17+
18+
group = 'com.graphql-java.examples'
19+
version = '0.0.1-SNAPSHOT'
20+
sourceCompatibility = 1.8
21+
22+
repositories {
23+
mavenCentral()
24+
}
25+
26+
27+
dependencies {
28+
compile "io.reactivex.rxjava2:rxjava:2.1.5"
29+
implementation('org.springframework.boot:spring-boot-starter-web')
30+
implementation('com.graphql-java:graphql-java:10.0')
31+
implementation('com.google.guava:guava:26.0-jre')
32+
testImplementation('org.springframework.boot:spring-boot-starter-test')
33+
}
53.4 KB
Binary file not shown.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#Sun Oct 07 10:24:43 AEDT 2018
2+
distributionBase=GRADLE_USER_HOME
3+
distributionPath=wrapper/dists
4+
zipStoreBase=GRADLE_USER_HOME
5+
zipStorePath=wrapper/dists
6+
distributionUrl=https\://services.gradle.org/distributions/gradle-4.8.1-all.zip

performance-checks/gradlew

Lines changed: 172 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)