Skip to content

Commit cb7ba81

Browse files
authored
Add example stress query (#583)
* Add stress query * Update stress query to simplify structure * Add instrumentation stress queries * Update log statement * Move instrumentation state to private class
1 parent 8760915 commit cb7ba81

File tree

3 files changed

+162
-0
lines changed

3 files changed

+162
-0
lines changed
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Copyright 2020 Expedia, Inc
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.expediagroup.graphql.examples.directives
18+
19+
import com.expediagroup.graphql.annotations.GraphQLDirective
20+
21+
/**
22+
* Used to verify the performance overhead of instrumentation on fields.
23+
* Marker directive only, does not have DirectiveWiring.
24+
*/
25+
@GraphQLDirective(
26+
name = TRACK_TIMES_INVOKED_DIRECTIVE_NAME,
27+
description = "If the field is marked with this directive, " +
28+
"we keep track of how many times this field was invoked per exection " +
29+
"and log the result server side through graphql-java Instrumentation"
30+
)
31+
annotation class TrackTimesInvoked
32+
33+
const val TRACK_TIMES_INVOKED_DIRECTIVE_NAME = "trackTimesInvoked"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
* Copyright 2020 Expedia, Inc
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.expediagroup.graphql.examples.instrumentation
18+
19+
import com.expediagroup.graphql.examples.directives.TRACK_TIMES_INVOKED_DIRECTIVE_NAME
20+
import graphql.ExecutionResult
21+
import graphql.execution.instrumentation.InstrumentationContext
22+
import graphql.execution.instrumentation.InstrumentationState
23+
import graphql.execution.instrumentation.SimpleInstrumentation
24+
import graphql.execution.instrumentation.SimpleInstrumentationContext
25+
import graphql.execution.instrumentation.parameters.InstrumentationExecutionParameters
26+
import graphql.execution.instrumentation.parameters.InstrumentationFieldFetchParameters
27+
import org.slf4j.LoggerFactory
28+
import org.springframework.stereotype.Component
29+
import java.util.concurrent.CompletableFuture
30+
import java.util.concurrent.ConcurrentHashMap
31+
32+
/**
33+
* Adds field count tracking in the instrumentation layer if [com.expediagroup.graphql.examples.directives.TrackTimesInvoked] is present.
34+
*/
35+
@Component
36+
class TrackTimesInvokedInstrumentation : SimpleInstrumentation() {
37+
38+
private val logger = LoggerFactory.getLogger(TrackTimesInvokedInstrumentation::class.java)
39+
40+
override fun createState(): InstrumentationState = TrackTimesInvokedInstrumenationState()
41+
42+
override fun beginFieldFetch(parameters: InstrumentationFieldFetchParameters): InstrumentationContext<Any> {
43+
if (parameters.field.getDirective(TRACK_TIMES_INVOKED_DIRECTIVE_NAME) != null) {
44+
(parameters.getInstrumentationState() as? TrackTimesInvokedInstrumenationState)?.incrementCount(parameters.field.name)
45+
}
46+
47+
return SimpleInstrumentationContext<Any>()
48+
}
49+
50+
override fun instrumentExecutionResult(executionResult: ExecutionResult, parameters: InstrumentationExecutionParameters): CompletableFuture<ExecutionResult> {
51+
val count = (parameters.getInstrumentationState() as? TrackTimesInvokedInstrumenationState)?.getCount()
52+
logger.info("TrackTimesInvokedInstrumentation fields invoked: $count")
53+
return super.instrumentExecutionResult(executionResult, parameters)
54+
}
55+
56+
/**
57+
* The state per execution for this Instrumentation
58+
*/
59+
private class TrackTimesInvokedInstrumenationState : InstrumentationState {
60+
61+
private val fieldCount = ConcurrentHashMap<String, Int>()
62+
63+
fun incrementCount(fieldName: String) {
64+
val currentCount = fieldCount.getOrDefault(fieldName, 0)
65+
fieldCount[fieldName] = currentCount.plus(1)
66+
}
67+
68+
fun getCount() = fieldCount.toString()
69+
}
70+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* Copyright 2020 Expedia, Inc
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
@file:Suppress("unused")
18+
19+
package com.expediagroup.graphql.examples.query
20+
21+
import com.expediagroup.graphql.examples.directives.TrackTimesInvoked
22+
import com.expediagroup.graphql.spring.operations.Query
23+
import io.netty.util.internal.ThreadLocalRandom
24+
import org.springframework.stereotype.Component
25+
import java.util.UUID
26+
27+
/**
28+
* Used to stress test the performance of running many data fetchers.
29+
* Tests properties vs functions vs suspend functions.
30+
*/
31+
@Component
32+
class StressQuery : Query {
33+
34+
fun stressNode(traceId: String?, count: Int?): List<StressNode> {
35+
val id = traceId ?: getRandomStringFromThread()
36+
return (1..(count ?: 1)).map { StressNode(id) }
37+
}
38+
}
39+
40+
@Suppress("MemberVisibilityCanBePrivate", "RedundantSuspendModifier")
41+
class StressNode(val traceId: String) {
42+
43+
val valueId: String = getRandomStringFromThread()
44+
45+
fun functionId(): String = getRandomStringFromThread()
46+
47+
suspend fun suspendId(): String = getRandomStringFromThread()
48+
49+
@TrackTimesInvoked
50+
fun loggingFunctionId(): String = getRandomStringFromThread()
51+
52+
@TrackTimesInvoked
53+
suspend fun suspendLoggingFunctionId(): String = getRandomStringFromThread()
54+
}
55+
56+
private fun getRandomStringFromThread(): String {
57+
val random = ThreadLocalRandom.current()
58+
return UUID(random.nextLong(), random.nextLong()).toString()
59+
}

0 commit comments

Comments
 (0)