refactor: cleanup coroutine scopes#500
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #500 +/- ##
==========================================
- Coverage 83.66% 83.65% -0.01%
==========================================
Files 152 152
Lines 4896 4894 -2
Branches 853 853
==========================================
- Hits 4096 4094 -2
Misses 498 498
Partials 302 302 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
| Branch | refactor/better-coroutine-scope |
| Testbed | ubuntu-latest |
🚨 1 Alert
| Benchmark | Measure Units | View | Benchmark Result (Result Δ%) | Lower Boundary (Limit %) |
|---|---|---|---|---|
| com.apurebase.kgraphql.RequestCachingBenchmark.invalidRequest | Throughput operations / second (ops/s) x 1e3 | 📈 plot 🚷 threshold 🚨 alert (🔔) | 35.42 ops/s x 1e3(-83.92%)Baseline: 220.31 ops/s x 1e3 | 126.24 ops/s x 1e3 (356.41%) |
Click to view all benchmark results
| Benchmark | Latency | Benchmark Result milliseconds (ms) (Result Δ%) | Upper Boundary milliseconds (ms) (Limit %) | Throughput | Benchmark Result operations / second (ops/s) (Result Δ%) | Lower Boundary operations / second (ops/s) (Limit %) |
|---|---|---|---|---|---|---|
| com.apurebase.kgraphql.FunctionExecutionBenchmark.benchmarkFunctionExecution | 📈 view plot 🚷 view threshold | 6,078,408.66 ops/s(+1.69%)Baseline: 5,977,390.47 ops/s | 5,507,281.10 ops/s (90.60%) | |||
| com.apurebase.kgraphql.ParallelExecutionBenchmark.queryBenchmark | 📈 view plot 🚷 view threshold | 768.99 ms(-0.21%)Baseline: 770.63 ms | 772.70 ms (99.52%) | |||
| com.apurebase.kgraphql.QueryBenchmark.largeList | 📈 view plot 🚷 view threshold | 4.42 ops/s(+51.59%)Baseline: 2.92 ops/s | -4.54 ops/s (-102.79%) | |||
| com.apurebase.kgraphql.QueryBenchmark.manyChildren | 📈 view plot 🚷 view threshold | 159.60 ops/s(-14.36%)Baseline: 186.36 ops/s | 135.74 ops/s (85.05%) | |||
| com.apurebase.kgraphql.QueryBenchmark.manyDataChildren | 📈 view plot 🚷 view threshold | 8.80 ops/s(-1.51%)Baseline: 8.93 ops/s | 8.66 ops/s (98.42%) | |||
| com.apurebase.kgraphql.QueryBenchmark.manyOperations | 📈 view plot 🚷 view threshold | 257.23 ops/s(-1.96%)Baseline: 262.37 ops/s | 151.96 ops/s (59.08%) | |||
| com.apurebase.kgraphql.QueryBenchmark.nestedObject | 📈 view plot 🚷 view threshold | 8,809.67 ops/s(+4.41%)Baseline: 8,437.38 ops/s | 6,022.97 ops/s (68.37%) | |||
| com.apurebase.kgraphql.RequestCachingBenchmark.invalidRequest | 📈 view plot 🚷 view threshold 🚨 view alert (🔔) | 35,420.50 ops/s(-83.92%)Baseline: 220,309.98 ops/s | 126,242.23 ops/s (356.41%) | |||
| com.apurebase.kgraphql.RequestCachingBenchmark.largeRequest | 📈 view plot 🚷 view threshold | 8,563.10 ops/s(+1.46%)Baseline: 8,439.89 ops/s | 7,623.27 ops/s (89.02%) | |||
| com.apurebase.kgraphql.RequestCachingBenchmark.smallRequest | 📈 view plot 🚷 view threshold | 12,924.17 ops/s(+2.00%)Baseline: 12,671.36 ops/s | 11,155.95 ops/s (86.32%) | |||
| com.apurebase.kgraphql.SimpleExecutionOverheadBenchmark.benchmark | 📈 view plot 🚷 view threshold | 459,765.69 ops/s(-2.18%)Baseline: 470,010.79 ops/s | 455,828.82 ops/s (99.14%) |
f44e1ee to
fb92944
Compare
|
Performance regression needs further analysis |
Remove coroutineContext from execution context and use one with the provided dispatcher.
fb92944 to
8e4332d
Compare
There was a problem hiding this comment.
1 issue found across 4 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="kgraphql/api/kgraphql.api">
<violation number="1" location="kgraphql/api/kgraphql.api:871">
P2: This changes a public constructor signature and introduces a binary-incompatible API break for existing consumers compiled against the previous 4-parameter constructor.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review, or fix all with cubic.
|
|
||
| public final class com/apurebase/kgraphql/schema/execution/ParallelRequestExecutor$ExecutionContext { | ||
| public fun <init> (Lkotlinx/coroutines/CoroutineScope;Lcom/apurebase/kgraphql/request/Variables;Lcom/apurebase/kgraphql/Context;Ljava/util/Map;)V | ||
| public fun <init> (Lcom/apurebase/kgraphql/request/Variables;Lcom/apurebase/kgraphql/Context;Ljava/util/Map;)V |
There was a problem hiding this comment.
P2: This changes a public constructor signature and introduces a binary-incompatible API break for existing consumers compiled against the previous 4-parameter constructor.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At kgraphql/api/kgraphql.api, line 871:
<comment>This changes a public constructor signature and introduces a binary-incompatible API break for existing consumers compiled against the previous 4-parameter constructor.</comment>
<file context>
@@ -868,10 +868,9 @@ public final class com/apurebase/kgraphql/schema/execution/ParallelRequestExecut
public final class com/apurebase/kgraphql/schema/execution/ParallelRequestExecutor$ExecutionContext {
- public fun <init> (Lkotlinx/coroutines/CoroutineScope;Lcom/apurebase/kgraphql/request/Variables;Lcom/apurebase/kgraphql/Context;Ljava/util/Map;)V
+ public fun <init> (Lcom/apurebase/kgraphql/request/Variables;Lcom/apurebase/kgraphql/Context;Ljava/util/Map;)V
public final fun getLoaders ()Ljava/util/Map;
public final fun getRequestContext ()Lcom/apurebase/kgraphql/Context;
</file context>
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
kgraphql/src/main/kotlin/com/apurebase/kgraphql/schema/execution/ParallelRequestExecutor.kt (1)
236-263: Consider simplifying thecoroutineScope { async { ... } }pattern.The current pattern wraps the function body in
coroutineScope { async { ... } }and returns aDeferred<ObjectNode>. However, sincecoroutineScopewaits for all children (including theasync) before returning, the returnedDeferredis always already-completed by the time the function returns.This adds overhead without benefit since:
- The
coroutineScopeblocks until theasynccompletes- Callers then call
.await()on an already-completedDeferredThe parallelism for child fields IS correctly preserved via the inner
asynccalls at lines 247 and 251. The issue is just the outer wrapper.Note: This may relate to the "Performance regression needs further analysis" comment in the PR. Consider measuring whether this pattern impacts performance for deeply nested queries.
♻️ Alternative: Simplify to return value directly
If the function is always awaited immediately by callers, consider:
- private suspend fun <T> createObjectNode( - ctx: ExecutionContext, - value: T, - node: Execution.Node, - type: Type - ): Deferred<ObjectNode> = coroutineScope { - async { + private suspend fun <T> createObjectNode( + ctx: ExecutionContext, + value: T, + node: Execution.Node, + type: Type + ): ObjectNode = coroutineScope { val objectNode = jsonNodeFactory.objectNode() // ... rest of implementation objectNode - } }This would require updating call sites to wrap in
asyncwhere parallelism is needed, but would remove the redundantasync/awaitoverhead.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@kgraphql/src/main/kotlin/com/apurebase/kgraphql/schema/execution/ParallelRequestExecutor.kt` around lines 236 - 263, The function createObjectNode currently wraps its work in coroutineScope { async { ... } } returning a Deferred that's already-completed; remove the redundant outer coroutineScope/async and make createObjectNode a suspend function that directly builds and returns an ObjectNode (keeping inner async calls for child fields that call handleFragment and handleProperty and awaiting those deferreds); update the function signature to return ObjectNode (not Deferred<ObjectNode>) and adjust all call sites that used .await() to call directly (or wrap in async there if true Deferred is needed) so you preserve parallelism of the child deferreds while eliminating the outer overhead.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@kgraphql/api/kgraphql.api`:
- Around line 870-875: The change removed CoroutineScope from the
ExecutionContext API causing a breaking change: restore backward compatibility
by reintroducing a constructor overload for
com.apurebase.kgraphql.schema.execution.ParallelRequestExecutor$ExecutionContext
that accepts (Variables, Context, Map, CoroutineScope) and re-add a getScope()
accessor (or provide a new method name that exposes the scope) so external
callers can still supply and read a custom scope; alternatively, add a
factory/helper method that accepts a CoroutineScope and constructs the existing
constructor, and mark the old/removed constructor as deprecated if you intend to
phase it out rather than immediately remove it.
---
Nitpick comments:
In
`@kgraphql/src/main/kotlin/com/apurebase/kgraphql/schema/execution/ParallelRequestExecutor.kt`:
- Around line 236-263: The function createObjectNode currently wraps its work in
coroutineScope { async { ... } } returning a Deferred that's already-completed;
remove the redundant outer coroutineScope/async and make createObjectNode a
suspend function that directly builds and returns an ObjectNode (keeping inner
async calls for child fields that call handleFragment and handleProperty and
awaiting those deferreds); update the function signature to return ObjectNode
(not Deferred<ObjectNode>) and adjust all call sites that used .await() to call
directly (or wrap in async there if true Deferred is needed) so you preserve
parallelism of the child deferreds while eliminating the outer overhead.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 4ec18236-ae73-47d6-b85f-99eefc23da30
📒 Files selected for processing (4)
kgraphql/api/kgraphql.apikgraphql/src/main/kotlin/com/apurebase/kgraphql/Extensions.ktkgraphql/src/main/kotlin/com/apurebase/kgraphql/schema/DefaultSchema.ktkgraphql/src/main/kotlin/com/apurebase/kgraphql/schema/execution/ParallelRequestExecutor.kt
| public final class com/apurebase/kgraphql/schema/execution/ParallelRequestExecutor$ExecutionContext { | ||
| public fun <init> (Lkotlinx/coroutines/CoroutineScope;Lcom/apurebase/kgraphql/request/Variables;Lcom/apurebase/kgraphql/Context;Ljava/util/Map;)V | ||
| public fun <init> (Lcom/apurebase/kgraphql/request/Variables;Lcom/apurebase/kgraphql/Context;Ljava/util/Map;)V | ||
| public final fun getLoaders ()Ljava/util/Map; | ||
| public final fun getRequestContext ()Lcom/apurebase/kgraphql/Context; | ||
| public final fun getScope ()Lkotlinx/coroutines/CoroutineScope; | ||
| public final fun getVariables ()Lcom/apurebase/kgraphql/request/Variables; | ||
| } |
There was a problem hiding this comment.
Breaking API change: ExecutionContext constructor and accessor modified.
The removal of CoroutineScope from the ExecutionContext constructor and the removal of getScope() constitute a breaking change for any consumers who:
- Construct
ExecutionContextdirectly with a custom scope - Access the scope via
getScope()for custom async work
Consider:
- Documenting this in release notes/migration guide
- If this is part of a minor/patch version, consider deprecation before removal
- If external consumers need scope access, consider alternative APIs (e.g., exposing structured concurrency helpers)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@kgraphql/api/kgraphql.api` around lines 870 - 875, The change removed
CoroutineScope from the ExecutionContext API causing a breaking change: restore
backward compatibility by reintroducing a constructor overload for
com.apurebase.kgraphql.schema.execution.ParallelRequestExecutor$ExecutionContext
that accepts (Variables, Context, Map, CoroutineScope) and re-add a getScope()
accessor (or provide a new method name that exposes the scope) so external
callers can still supply and read a custom scope; alternatively, add a
factory/helper method that accepts a CoroutineScope and constructs the existing
constructor, and mark the old/removed constructor as deprecated if you intend to
phase it out rather than immediately remove it.
Remove coroutineContext from execution context and use one with the provided dispatcher.