Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

KTOR-8244: Fixed an issue where canceling the incoming flow of OkHttpSSESession/DefaultClientSSESession failed to disconnect the SSE session. #4694

Merged
merged 3 commits into from
Feb 26, 2025

Conversation

hehua2008
Copy link
Contributor

Fixed an issue where canceling the incoming flow of OkHttpSSESession failed to disconnect the SSE session.

Subsystem
Client
ktor-client/ktor-client-okhttp

Motivation
Refer to a bug/ticket #4692.
In the OkHttpSSESession implementation of SSESession, cancel incoming flow will NOT trigger serverSentEventsSource.cancel(), which will keep SSE still connecting !

Solution

  • First, val incoming: Flow<ServerSentEvent> in OkHttpSSESession should always return the same Flow instance, just as DefaultClientSSESession did.

  • Second, cancel _incoming.receiveAsFlow() will just cancel the Flow but will NOT cancel the _incoming Channel, so we should use _incoming.consumeAsFlow() instead.

  • Third, if incoming.trySendBlocking(ServerSentEvent(data, type, id)) fails with a CancellationException, we should rethrow the CancellationException to let fun onFailure(eventSource: EventSource, t: Throwable?, response: Response?) handle it and close the SSE session.

@e5l
Copy link
Member

e5l commented Feb 21, 2025

Hey @hehua2008, lgtm. Could you add a test, so we can merge? :)

@e5l e5l requested a review from marychatte February 21, 2025 14:27
@e5l e5l self-assigned this Feb 21, 2025
@hehua2008 hehua2008 changed the title Fixed an issue where canceling the incoming flow of OkHttpSSESession failed to disconnect the SSE session. Fixed an issue where canceling the incoming flow of OkHttpSSESession/DefaultClientSSESession failed to disconnect the SSE session. Feb 21, 2025
@hehua2008
Copy link
Contributor Author

For same bug in DefaultClientSSESession:
Because catch operator only catch throwable occurs in upstream flow, so we use onCompletion operator instead to handle CancellationException occurs in either upstream flow or downstream flow.

    }.catch { cause ->
        when (cause) {
            is CancellationException -> {
                // CancellationException will be handled by onCompletion operator
            }

            else -> {
                LOGGER.trace { "Error during SSE session processing: $cause" }
                close()
                throw cause
            }
        }
    }.onCompletion { cause ->
        // Because catch operator only catch throwable occurs in upstream flow, so we use onCompletion operator instead
        // to handle CancellationException occurs in either upstream flow or downstream flow.
        if (cause is CancellationException) {
            close()
        }
    }

@hehua2008
Copy link
Contributor Author

Hey @hehua2008, lgtm. Could you add a test, so we can merge? :)

I have added testCancelSseSession in ServerSentEventsTest for ktor-client:

    @Test
    fun testCancelSseSession() = clientTests {
        config {
            install(SSE)
        }

        test { client ->
            coroutineScope {
                val job = launch {
                    val session = client.serverSentEventsSession("$TEST_SERVER/sse/hello?times=20&interval=100")
                    try {
                        session.incoming.collect()
                    } finally {
                        withContext(NonCancellable) {
                            delay(500)
                            assertFalse(session.isActive)
                        }
                    }
                }
                delay(500)
                job.cancelAndJoin()
            }
        }
    }

Copy link
Member

@e5l e5l left a comment

Choose a reason for hiding this comment

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

lgtm

@osipxd
Copy link
Member

osipxd commented Feb 24, 2025

Hey @hehua2008, thank you for the PR! Could you please fix import ordering in DefaultClientSSESession?

@hehua2008 hehua2008 force-pushed the fix-cancel-OkHttpSSESession branch from 8912c86 to a4c13db Compare February 24, 2025 17:08
@hehua2008
Copy link
Contributor Author

Hey @hehua2008, thank you for the PR! Could you please fix import ordering in DefaultClientSSESession?

Sorry for that, I have fixed it.

@hehua2008 hehua2008 force-pushed the fix-cancel-OkHttpSSESession branch from a4c13db to b0d6f5e Compare February 24, 2025 17:15
@e5l e5l enabled auto-merge (squash) February 24, 2025 18:45
auto-merge was automatically disabled February 26, 2025 00:43

Head branch was pushed to by a user without write access

@hehua2008 hehua2008 force-pushed the fix-cancel-OkHttpSSESession branch from b0d6f5e to 3f6c365 Compare February 26, 2025 00:43
@e5l e5l merged commit 9e20697 into ktorio:main Feb 26, 2025
13 of 15 checks passed
@osipxd osipxd changed the title Fixed an issue where canceling the incoming flow of OkHttpSSESession/DefaultClientSSESession failed to disconnect the SSE session. KTOR-8244: Fixed an issue where canceling the incoming flow of OkHttpSSESession/DefaultClientSSESession failed to disconnect the SSE session. Feb 26, 2025
@Savrov
Copy link
Contributor

Savrov commented Feb 27, 2025

When we can expect it to be released?

@Stexxe
Copy link
Contributor

Stexxe commented Feb 27, 2025

In the next patch release of Ktor 3.1.2.

@Savrov
Copy link
Contributor

Savrov commented Mar 4, 2025

I would like to know some est. date, cause it's a critical defect in our app and we can not release it without that fix.

Thank you

@e5l
Copy link
Member

e5l commented Mar 4, 2025

Hey, @Savrov! We usually do monthly releases, and the next one is planned for the last week of March.
If you want to check out the build with a fix, please consider checking https://ktor.io/eap. They are the same builds from the main branch, but published daily.

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.

[Bug] Cancel flow of SSESession.incoming will not disconnect connection in OkHttpSSESession implementation
5 participants