Skip to content

Commit eb9cedd

Browse files
samuelAndalonNorman-Namclaude
authored
feat(10.x.x): make graphqlGenerateSDL worker JVM args configurable (#2197)
### 📝 Description cherry pick #2182 Co-authored-by: Norman <vu.hoang.nam@moneyforward.co.jp> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 681dca9 commit eb9cedd

6 files changed

Lines changed: 172 additions & 0 deletions

File tree

plugins/graphql-kotlin-gradle-plugin/src/main/kotlin/com/expediagroup/graphql/plugin/gradle/GraphQLGradlePlugin.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ class GraphQLGradlePlugin : Plugin<Project> {
154154

155155
val generateSchemaTask = project.tasks.named(GENERATE_SDL_TASK_NAME, GraphQLGenerateSDLTask::class.java).get()
156156
generateSchemaTask.packages.set(supportedPackages)
157+
generateSchemaTask.jvmArguments.convention(extension.schemaExtension.jvmArguments)
157158
}
158159

159160
if (extension.isGraalVmConfigurationAvailable()) {

plugins/graphql-kotlin-gradle-plugin/src/main/kotlin/com/expediagroup/graphql/plugin/gradle/GraphQLPluginExtension.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,14 @@ open class GraphQLPluginClientExtension {
113113
open class GraphQLPluginSchemaExtension {
114114
/** List of supported packages that can contain GraphQL schema type definitions. */
115115
var packages: List<String> = emptyList()
116+
117+
/**
118+
* JVM arguments passed to the process-isolated worker that generates the SDL, e.g. `listOf("-Xmx2g")`.
119+
*
120+
* SDL generation runs in a forked JVM that uses the Gradle default heap. Schemas large enough to
121+
* exhaust that heap (resulting in an `OutOfMemoryError`) can raise it by configuring these arguments.
122+
*/
123+
var jvmArguments: List<String> = emptyList()
116124
}
117125

118126
open class GraphQLPluginGraalVmExtension {

plugins/graphql-kotlin-gradle-plugin/src/main/kotlin/com/expediagroup/graphql/plugin/gradle/tasks/GraphQLGenerateSDLTask.kt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,18 @@ abstract class GraphQLGenerateSDLTask : SourceTask() {
6464
@OutputFile
6565
val schemaFile: RegularFileProperty = project.objects.fileProperty()
6666

67+
/**
68+
* JVM arguments passed to the process-isolated worker that generates the SDL, e.g. `listOf("-Xmx2g")`.
69+
*
70+
* SDL generation runs in a forked JVM that uses the Gradle default heap. Schemas large enough to
71+
* exhaust that heap (resulting in an `OutOfMemoryError`) can raise it by configuring these arguments.
72+
* Defaults to an empty list, i.e. no additional JVM arguments.
73+
*/
74+
@Input
75+
@Optional
76+
@Option(option = "jvm-args", description = "JVM arguments for the SDL generation worker, e.g. -Xmx2g")
77+
val jvmArguments: ListProperty<String> = project.objects.listProperty(String::class.java)
78+
6779
@get:Inject
6880
abstract val workerExecutor: WorkerExecutor
6981

@@ -101,8 +113,10 @@ abstract class GraphQLGenerateSDLTask : SourceTask() {
101113
val workQueue: WorkQueue = workerExecutor.processIsolation { workerSpec: ProcessWorkerSpec ->
102114
workerSpec.forkOptions {
103115
it.setExecutable(launcher.get().executablePath.asFile)
116+
it.jvmArgs(jvmArguments.getOrElse(emptyList()))
104117
}
105118
logger.debug("worker executable: \n${workerSpec.forkOptions.executable}")
119+
logger.debug("worker jvm args: \n${workerSpec.forkOptions.allJvmArgs}")
106120

107121
val workerClasspath = pluginClasspath.plus(projectClasspath).plus(source.files)
108122
workerSpec.classpath.from(workerClasspath)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
* Copyright 2026 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.plugin.gradle.tasks
18+
19+
import com.expediagroup.graphql.plugin.gradle.GraphQLGradlePlugin
20+
import com.expediagroup.graphql.plugin.gradle.GraphQLPluginExtension
21+
import org.gradle.api.internal.project.ProjectInternal
22+
import org.gradle.testfixtures.ProjectBuilder
23+
import kotlin.test.Test
24+
import kotlin.test.assertEquals
25+
import kotlin.test.assertTrue
26+
27+
class GraphQLGenerateSDLTaskTest {
28+
29+
@Test
30+
fun `jvmArguments defaults to an empty list`() {
31+
val project = ProjectBuilder.builder().build()
32+
project.pluginManager.apply("java")
33+
project.pluginManager.apply(GraphQLGradlePlugin::class.java)
34+
35+
val task = project.tasks.getByName(GENERATE_SDL_TASK_NAME) as GraphQLGenerateSDLTask
36+
assertTrue(task.jvmArguments.get().isEmpty())
37+
}
38+
39+
@Test
40+
fun `jvmArguments configured on the schema extension are propagated to the task`() {
41+
val project = ProjectBuilder.builder().build()
42+
project.pluginManager.apply("java")
43+
project.pluginManager.apply(GraphQLGradlePlugin::class.java)
44+
45+
val extension = project.extensions.getByType(GraphQLPluginExtension::class.java)
46+
extension.schema {
47+
it.packages = listOf("com.example")
48+
it.jvmArguments = listOf("-Xmx2g", "-XX:+UseG1GC")
49+
}
50+
51+
// extension configuration is applied to the task in an afterEvaluate hook
52+
(project as ProjectInternal).evaluate()
53+
54+
val task = project.tasks.getByName(GENERATE_SDL_TASK_NAME) as GraphQLGenerateSDLTask
55+
assertEquals(listOf("-Xmx2g", "-XX:+UseG1GC"), task.jvmArguments.get())
56+
}
57+
58+
@Test
59+
fun `jvmArguments set directly on the task are not overridden by the schema extension`() {
60+
val project = ProjectBuilder.builder().build()
61+
project.pluginManager.apply("java")
62+
project.pluginManager.apply(GraphQLGradlePlugin::class.java)
63+
64+
val task = project.tasks.getByName(GENERATE_SDL_TASK_NAME) as GraphQLGenerateSDLTask
65+
task.jvmArguments.set(listOf("-Xmx4g"))
66+
67+
val extension = project.extensions.getByType(GraphQLPluginExtension::class.java)
68+
extension.schema {
69+
it.packages = listOf("com.example")
70+
it.jvmArguments = listOf("-Xmx2g")
71+
}
72+
73+
// extension configuration is applied to the task in an afterEvaluate hook
74+
(project as ProjectInternal).evaluate()
75+
76+
assertEquals(listOf("-Xmx4g"), task.jvmArguments.get())
77+
}
78+
}

website/docs/plugins/gradle-plugin-tasks.mdx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,8 @@ graphql {
171171
schema {
172172
// List of supported packages that can contain GraphQL schema type definitions
173173
packages = listOf("com.example")
174+
// Optional JVM arguments for the SDL generation worker, e.g. to raise the heap for large schemas
175+
jvmArguments = listOf("-Xmx2g")
174176
}
175177
}
176178
```
@@ -239,6 +241,8 @@ graphql {
239241
}
240242
schema {
241243
packages = ["com.example"]
244+
// Optional JVM arguments for the SDL generation worker, e.g. to raise the heap for large schemas
245+
jvmArguments = ["-Xmx2g"]
242246
}
243247
}
244248
```
@@ -352,6 +356,7 @@ GraphQL types.
352356
| -------- | ---- | -------- | ----------- |
353357
| `packages` | `List<String>` | yes | List of supported packages that can be scanned to generate SDL. |
354358
| `schemaFile` | File | | Target GraphQL schema file to be generated.<br/>**Default value is:** `${project.buildDir}/schema.graphql` |
359+
| `jvmArguments` | `List<String>` | | JVM arguments passed to the process-isolated worker that generates the SDL, e.g. `listOf("-Xmx2g")`. Useful for raising the heap when generating large schemas that would otherwise fail with an `OutOfMemoryError`.<br/>**Default value is:** empty list |
355360

356361
By default, this task will attempt to generate the schema using `NoopSchemaGeneratorHooks`. If you need to customize your
357362
schema generation process, you will need to provide your custom instance of `SchemaGeneratorHooksProvider` service provider.

website/docs/plugins/gradle-plugin-usage-sdl.mdx

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,72 @@ This task does not automatically configure itself to be part of your build lifec
8080
invoke it OR configure it as a dependency of some other task.
8181
:::
8282

83+
## Configuring the SDL Generation Heap
84+
85+
SDL generation runs in a process-isolated worker JVM that uses the Gradle default heap. Large schemas can exhaust that
86+
heap and fail with an `OutOfMemoryError`. You can raise the heap (or pass any other JVM arguments) to the worker through
87+
the optional `jvmArguments` property.
88+
89+
<Tabs
90+
defaultValue="kotlin"
91+
values={[
92+
{ label: 'Kotlin', value: 'kotlin' },
93+
{ label: 'Groovy', value: 'groovy' }
94+
]
95+
}>
96+
97+
<TabItem value="kotlin">
98+
99+
```kotlin
100+
// build.gradle.kts
101+
import com.expediagroup.graphql.plugin.gradle.graphql
102+
103+
graphql {
104+
schema {
105+
packages = listOf("com.example")
106+
jvmArguments = listOf("-Xmx2g")
107+
}
108+
}
109+
```
110+
111+
Above configuration is equivalent to the following task definition
112+
113+
```kotlin
114+
// build.gradle.kts
115+
import com.expediagroup.graphql.plugin.gradle.tasks.GraphQLGenerateSDLTask
116+
117+
val graphqlGenerateSDL by tasks.getting(GraphQLGenerateSDLTask::class) {
118+
packages.set(listOf("com.example"))
119+
jvmArguments.set(listOf("-Xmx2g"))
120+
}
121+
```
122+
123+
</TabItem>
124+
<TabItem value="groovy">
125+
126+
```groovy
127+
// build.gradle
128+
graphql {
129+
schema {
130+
packages = ["com.example"]
131+
jvmArguments = ["-Xmx2g"]
132+
}
133+
}
134+
```
135+
136+
Above configuration is equivalent to the following task definition
137+
138+
```groovy
139+
//build.gradle
140+
graphqlGenerateSDL {
141+
packages = ["com.example"]
142+
jvmArguments = ["-Xmx2g"]
143+
}
144+
```
145+
146+
</TabItem>
147+
</Tabs>
148+
83149
## Using Custom Hooks Provider
84150

85151
Plugin will default to use `NoopSchemaGeneratorHooks` to generate target GraphQL schema. If your project uses custom hooks

0 commit comments

Comments
 (0)