Skip to content

KTOR-9545 Curl: Attach bodyChannel to correct job#5564

Merged
osipxd merged 2 commits intomainfrom
osipxd/curl-call-context-propagation
Apr 30, 2026
Merged

KTOR-9545 Curl: Attach bodyChannel to correct job#5564
osipxd merged 2 commits intomainfrom
osipxd/curl-call-context-propagation

Conversation

@osipxd
Copy link
Copy Markdown
Member

@osipxd osipxd commented Apr 29, 2026

Subsystem
ktor-client-curl

Motivation
KTOR-9545 Curl: body channel not cancelled when caller scope is cancelled

Solution
Attach bodyChannel to callContext instead of request.executionContext. Add a shared regression test for all engines.

@osipxd osipxd self-assigned this Apr 29, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 29, 2026

📝 Walkthrough

Walkthrough

Propagates the request's call Job through the curl engine, switches cancellation/cleanup registration to use callContext, centralizes easy-handle removal in a helper, and updates tests/utilities to use Duration-based timeouts and add a cancellation test.

Changes

Cohort / File(s) Summary
Curl engine core
ktor-client/ktor-client-curl/desktop/src/io/ktor/client/engine/curl/CurlClientEngine.kt, ktor-client/ktor-client-curl/desktop/src/io/ktor/client/engine/curl/CurlProcessor.kt
Pass callContext: Job into request creation and attach cancellation/cleanup handlers to callContext instead of the previous execution context.
Curl multi-API internals
ktor-client/ktor-client-curl/desktop/src/io/ktor/client/engine/curl/internal/CurlMultiApiHandler.kt, ktor-client/ktor-client-curl/desktop/src/io/ktor/client/engine/curl/internal/CurlRaw.kt
Use request.callContext for request/response body objects, rename executionContextcallContext, add removeEasyHandle helper to centralize handle removal and ensure completion/disposal on cancellation.
Tests & utilities
ktor-client/ktor-client-tests/common/test/io/ktor/client/tests/utils/WaitUtils.kt, ktor-client/ktor-client-tests/common/test/io/ktor/client/tests/ContentTest.kt
Refactor waitForCondition to Duration-based monotonic timeout; add testBodyChannelCancelledWhenCallerScopeIsCancelled; replace numeric timeout with Duration and adjust a response-read loop.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

bug

Suggested reviewers

  • bjhham
  • e5l
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 14.29% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The PR title clearly and concisely describes the main change: attaching the bodyChannel to the correct job in the Curl engine, directly addressing KTOR-9545.
Description check ✅ Passed The PR description includes all required template sections: Subsystem, Motivation (with ticket reference), and Solution with implementation details.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch osipxd/curl-call-context-propagation

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
Review rate limit: 7/8 reviews remaining, refill in 7 minutes and 30 seconds.

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
ktor-client/ktor-client-tests/common/test/io/ktor/client/tests/ContentTest.kt (1)

398-398: Use a backticked descriptive test name.

Please rename this to something like fun `body channel is cancelled when caller scope is cancelled`() to match the shared test style in this repo.

As per coding guidelines "Use descriptive test names in backticks: describe what is being tested."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@ktor-client/ktor-client-tests/common/test/io/ktor/client/tests/ContentTest.kt`
at line 398, Rename the test function
testBodyChannelCancelledWhenCallerScopeIsCancelled to use a backticked
descriptive name to match repo style; change the function declaration fun
testBodyChannelCancelledWhenCallerScopeIsCancelled() = ... to fun `body channel
is cancelled when caller scope is cancelled`() = ... so the test reads as a
descriptive sentence and follows the backticked test naming convention (update
the function name in ContentTest.kt accordingly).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In
`@ktor-client/ktor-client-tests/common/test/io/ktor/client/tests/ContentTest.kt`:
- Line 398: Rename the test function
testBodyChannelCancelledWhenCallerScopeIsCancelled to use a backticked
descriptive name to match repo style; change the function declaration fun
testBodyChannelCancelledWhenCallerScopeIsCancelled() = ... to fun `body channel
is cancelled when caller scope is cancelled`() = ... so the test reads as a
descriptive sentence and follows the backticked test naming convention (update
the function name in ContentTest.kt accordingly).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 0774243b-fd18-42aa-a266-1b48e8b62b60

📥 Commits

Reviewing files that changed from the base of the PR and between 3f1bca4 and b59bacf.

📒 Files selected for processing (5)
  • ktor-client/ktor-client-curl/desktop/src/io/ktor/client/engine/curl/CurlClientEngine.kt
  • ktor-client/ktor-client-curl/desktop/src/io/ktor/client/engine/curl/CurlProcessor.kt
  • ktor-client/ktor-client-curl/desktop/src/io/ktor/client/engine/curl/internal/CurlMultiApiHandler.kt
  • ktor-client/ktor-client-tests/common/test/io/ktor/client/tests/ContentTest.kt
  • ktor-client/ktor-client-tests/common/test/io/ktor/client/tests/utils/WaitUtils.kt

@osipxd osipxd marked this pull request as draft April 29, 2026 13:27
@osipxd osipxd force-pushed the osipxd/curl-call-context-propagation branch 3 times, most recently from 6ba8104 to 2809649 Compare April 29, 2026 13:58
@osipxd osipxd marked this pull request as ready for review April 29, 2026 13:58
@osipxd osipxd enabled auto-merge (rebase) April 29, 2026 13:58
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
ktor-client/ktor-client-tests/common/test/io/ktor/client/tests/ContentTest.kt (1)

398-398: Use a backticked descriptive test name (Line 398).

Please rename the new test to backtick style to match the repository test convention.

✏️ Suggested rename
-    fun testBodyChannelCancelledWhenCallerScopeIsCancelled() = clientTests(except("Apache5")) {
+    fun `body channel is cancelled when caller scope is cancelled`() = clientTests(except("Apache5")) {

As per coding guidelines: **/*Test.kt: Use descriptive test names in backticks: describe what is being tested.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@ktor-client/ktor-client-tests/common/test/io/ktor/client/tests/ContentTest.kt`
at line 398, Rename the test function
testBodyChannelCancelledWhenCallerScopeIsCancelled to a backticked descriptive
Kotlin test name to follow repo conventions; change the declaration fun
testBodyChannelCancelledWhenCallerScopeIsCancelled() =
clientTests(except("Apache5")) { ... } to use a backticked string identifier
(for example: fun `body channel is cancelled when caller scope is cancelled`() =
clientTests(except("Apache5")) { ... }), keeping the existing clientTests(...)
call and body unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@ktor-client/ktor-client-curl/desktop/src/io/ktor/client/engine/curl/internal/CurlMultiApiHandler.kt`:
- Around line 253-258: In removeEasyHandle,
processCancelledEasyHandle(easyHandle, cause) can throw and prevent
handler.responseCompletable.completeExceptionally and handler.dispose from
running; wrap processCancelledEasyHandle in a try and move
handler.responseCompletable.completeExceptionally(cause) and handler.dispose()
into a finally block so they always run; also guard
completeExceptionally/dispose with their own minimal try/catch to avoid masking
the original exception. Ensure references to EasyHandle, removeEasyHandle,
processCancelledEasyHandle, and RequestHolder.dispose are used to locate the
changes.

---

Nitpick comments:
In
`@ktor-client/ktor-client-tests/common/test/io/ktor/client/tests/ContentTest.kt`:
- Line 398: Rename the test function
testBodyChannelCancelledWhenCallerScopeIsCancelled to a backticked descriptive
Kotlin test name to follow repo conventions; change the declaration fun
testBodyChannelCancelledWhenCallerScopeIsCancelled() =
clientTests(except("Apache5")) { ... } to use a backticked string identifier
(for example: fun `body channel is cancelled when caller scope is cancelled`() =
clientTests(except("Apache5")) { ... }), keeping the existing clientTests(...)
call and body unchanged.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 17afffb9-0314-45aa-a5f8-a939a9d9e052

📥 Commits

Reviewing files that changed from the base of the PR and between b59bacf and 2809649.

📒 Files selected for processing (6)
  • ktor-client/ktor-client-curl/desktop/src/io/ktor/client/engine/curl/CurlClientEngine.kt
  • ktor-client/ktor-client-curl/desktop/src/io/ktor/client/engine/curl/CurlProcessor.kt
  • ktor-client/ktor-client-curl/desktop/src/io/ktor/client/engine/curl/internal/CurlMultiApiHandler.kt
  • ktor-client/ktor-client-curl/desktop/src/io/ktor/client/engine/curl/internal/CurlRaw.kt
  • ktor-client/ktor-client-tests/common/test/io/ktor/client/tests/ContentTest.kt
  • ktor-client/ktor-client-tests/common/test/io/ktor/client/tests/utils/WaitUtils.kt
🚧 Files skipped from review as they are similar to previous changes (3)
  • ktor-client/ktor-client-curl/desktop/src/io/ktor/client/engine/curl/CurlClientEngine.kt
  • ktor-client/ktor-client-curl/desktop/src/io/ktor/client/engine/curl/CurlProcessor.kt
  • ktor-client/ktor-client-tests/common/test/io/ktor/client/tests/utils/WaitUtils.kt

@osipxd osipxd force-pushed the osipxd/curl-call-context-propagation branch from 2809649 to a9deee3 Compare April 29, 2026 15:17
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
ktor-client/ktor-client-tests/common/test/io/ktor/client/tests/ContentTest.kt (1)

398-398: Use backtick test naming for this new test function.

Please rename the function at Line 398 to a descriptive backtick name to match test-file conventions.

♻️ Suggested rename
-    fun testBodyChannelCancelledWhenCallerScopeIsCancelled() = clientTests(except("Apache5")) {
+    fun `body channel is cancelled when caller scope is cancelled`() = clientTests(except("Apache5")) {

As per coding guidelines: **/*Test.kt: Tests must use descriptive test names in backticks: describe what is being tested.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@ktor-client/ktor-client-tests/common/test/io/ktor/client/tests/ContentTest.kt`
at line 398, Rename the test function
testBodyChannelCancelledWhenCallerScopeIsCancelled to use a backtick descriptive
name (e.g. `body channel cancelled when caller scope is cancelled`) by changing
the declaration fun testBodyChannelCancelledWhenCallerScopeIsCancelled() =
clientTests(...) to fun `body channel cancelled when caller scope is
cancelled`() = clientTests(...); update any internal references to the function
name if present and keep the existing implementation and test registration
intact (look for the function symbol
testBodyChannelCancelledWhenCallerScopeIsCancelled in ContentTest.kt).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@ktor-client/ktor-client-tests/common/test/io/ktor/client/tests/utils/WaitUtils.kt`:
- Around line 19-24: The loop that polls until timeMark.hasNotPassedNow() uses
yield() causing busy-waiting; replace the tight yield() call with a suspending
delay (e.g., a small fixed delay like 20.milliseconds or delay(50)) inside the
while so the condition() check yields the CPU without spinning. Update the
polling loop that references timeMark.hasNotPassedNow() and condition() to call
delay(...) instead of yield() to prevent CPU burn and stabilize tests.

---

Nitpick comments:
In
`@ktor-client/ktor-client-tests/common/test/io/ktor/client/tests/ContentTest.kt`:
- Line 398: Rename the test function
testBodyChannelCancelledWhenCallerScopeIsCancelled to use a backtick descriptive
name (e.g. `body channel cancelled when caller scope is cancelled`) by changing
the declaration fun testBodyChannelCancelledWhenCallerScopeIsCancelled() =
clientTests(...) to fun `body channel cancelled when caller scope is
cancelled`() = clientTests(...); update any internal references to the function
name if present and keep the existing implementation and test registration
intact (look for the function symbol
testBodyChannelCancelledWhenCallerScopeIsCancelled in ContentTest.kt).
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 8e85183b-fa8f-4a78-bccc-31a5fb91f597

📥 Commits

Reviewing files that changed from the base of the PR and between 2809649 and a9deee3.

📒 Files selected for processing (6)
  • ktor-client/ktor-client-curl/desktop/src/io/ktor/client/engine/curl/CurlClientEngine.kt
  • ktor-client/ktor-client-curl/desktop/src/io/ktor/client/engine/curl/CurlProcessor.kt
  • ktor-client/ktor-client-curl/desktop/src/io/ktor/client/engine/curl/internal/CurlMultiApiHandler.kt
  • ktor-client/ktor-client-curl/desktop/src/io/ktor/client/engine/curl/internal/CurlRaw.kt
  • ktor-client/ktor-client-tests/common/test/io/ktor/client/tests/ContentTest.kt
  • ktor-client/ktor-client-tests/common/test/io/ktor/client/tests/utils/WaitUtils.kt
🚧 Files skipped from review as they are similar to previous changes (3)
  • ktor-client/ktor-client-curl/desktop/src/io/ktor/client/engine/curl/CurlClientEngine.kt
  • ktor-client/ktor-client-curl/desktop/src/io/ktor/client/engine/curl/CurlProcessor.kt
  • ktor-client/ktor-client-curl/desktop/src/io/ktor/client/engine/curl/internal/CurlRaw.kt

@osipxd osipxd force-pushed the osipxd/curl-call-context-propagation branch from a9deee3 to 3c5b5c3 Compare April 29, 2026 15:27
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
ktor-client/ktor-client-tests/common/test/io/ktor/client/tests/ContentTest.kt (1)

397-399: Use a backticked descriptive name for this new test.

Please rename the test at Line 398 to the backticked descriptive style used by project test guidelines.

Suggested rename
-    fun testBodyChannelCancelledWhenCallerScopeIsCancelled() = clientTests(except("Apache5")) {
+    fun `body channel is cancelled when caller scope is cancelled`() = clientTests(except("Apache5")) {

As per coding guidelines, **/*Test.kt: "Use descriptive test names in backticks: describe what is being tested."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@ktor-client/ktor-client-tests/common/test/io/ktor/client/tests/ContentTest.kt`
around lines 397 - 399, The test function named
testBodyChannelCancelledWhenCallerScopeIsCancelled should be renamed to a
backticked descriptive name per project guidelines; locate the function
declaration fun testBodyChannelCancelledWhenCallerScopeIsCancelled() and change
it to use a backticked string, for example fun `body channel is cancelled when
caller scope is cancelled`(), keeping the `@Test` annotation and the existing
clientTests(...) invocation unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In
`@ktor-client/ktor-client-tests/common/test/io/ktor/client/tests/ContentTest.kt`:
- Around line 397-399: The test function named
testBodyChannelCancelledWhenCallerScopeIsCancelled should be renamed to a
backticked descriptive name per project guidelines; locate the function
declaration fun testBodyChannelCancelledWhenCallerScopeIsCancelled() and change
it to use a backticked string, for example fun `body channel is cancelled when
caller scope is cancelled`(), keeping the `@Test` annotation and the existing
clientTests(...) invocation unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: c39f8481-4548-439e-a75c-94fe7d5ab4c3

📥 Commits

Reviewing files that changed from the base of the PR and between a9deee3 and 3c5b5c3.

📒 Files selected for processing (6)
  • ktor-client/ktor-client-curl/desktop/src/io/ktor/client/engine/curl/CurlClientEngine.kt
  • ktor-client/ktor-client-curl/desktop/src/io/ktor/client/engine/curl/CurlProcessor.kt
  • ktor-client/ktor-client-curl/desktop/src/io/ktor/client/engine/curl/internal/CurlMultiApiHandler.kt
  • ktor-client/ktor-client-curl/desktop/src/io/ktor/client/engine/curl/internal/CurlRaw.kt
  • ktor-client/ktor-client-tests/common/test/io/ktor/client/tests/ContentTest.kt
  • ktor-client/ktor-client-tests/common/test/io/ktor/client/tests/utils/WaitUtils.kt
🚧 Files skipped from review as they are similar to previous changes (4)
  • ktor-client/ktor-client-curl/desktop/src/io/ktor/client/engine/curl/CurlClientEngine.kt
  • ktor-client/ktor-client-curl/desktop/src/io/ktor/client/engine/curl/CurlProcessor.kt
  • ktor-client/ktor-client-tests/common/test/io/ktor/client/tests/utils/WaitUtils.kt
  • ktor-client/ktor-client-curl/desktop/src/io/ktor/client/engine/curl/internal/CurlRaw.kt

@osipxd osipxd merged commit ff6cb6d into main Apr 30, 2026
23 checks passed
@osipxd osipxd deleted the osipxd/curl-call-context-propagation branch April 30, 2026 06:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants