-
Notifications
You must be signed in to change notification settings - Fork 227
feat: concurrent message dispatch across all transports #788
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
Changes from all commits
89cea04
0274fab
2147ce3
c3a337e
2267a15
320f9ab
bed090e
39dee98
33ba1e3
074cc32
52477eb
4f74f9e
0d8999b
57e0cd2
39c1fcf
6c33d94
e43dc77
8b3a51e
f11c623
78b7f21
1783558
e7c671b
9cd31ad
8e22f9d
e98e66f
2fefbbf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -80,7 +80,7 @@ public class SseClientTransport( | |
| reconnectionTime = reconnectionTime, | ||
| block = requestBuilder, | ||
| ) | ||
| scope = CoroutineScope(session.coroutineContext + SupervisorJob()) | ||
| scope = CoroutineScope(session.coroutineContext + SupervisorJob(session.coroutineContext[Job])) | ||
|
|
||
| job = scope.launch(CoroutineName("SseMcpClientTransport.connect#${hashCode()}")) { | ||
| collectMessages() | ||
|
|
@@ -163,17 +163,31 @@ public class SseClientTransport( | |
| } | ||
| } | ||
|
|
||
| private suspend fun handleMessage(data: String) { | ||
| private fun handleMessage(data: String) { | ||
| try { | ||
| val message = McpJson.decodeFromString<JSONRPCMessage>(data) | ||
| _onMessage(message) | ||
| launchMessageHandler(message) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If the user provides a non thread-safe handler, a data race may occur
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This also applies to other launchMessageHandlers in other transports
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's a paradox on making message handling concurrent and accepting any non thread-safe handler. While the old messaging handling has been sequential, it has never guaranteed thread-safety, as clients could always send parallel messages through multiple connections to the same server instance. Partial (single-session level) thread-safety is never real safety, are we still to keep the behavior? It can be done by supporting custom messaging handling dispatcher with no parallelism by default. |
||
| } catch (e: SerializationException) { | ||
| _onError(e) | ||
| } | ||
| } | ||
|
|
||
| private fun launchMessageHandler(message: JSONRPCMessage) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not move this method to AbstractServerTransport if it is repeated everywhere? |
||
| scope.launch(CoroutineName("SseMcpClientTransport.message#${hashCode()}")) { | ||
| try { | ||
| _onMessage(message) | ||
| } catch (e: CancellationException) { | ||
| throw e | ||
| } catch (e: Throwable) { | ||
| logger.error(e) { "Error processing message" } | ||
| _onError(e) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| override suspend fun closeResources() { | ||
| withContext(NonCancellable) { | ||
| invokeOnCloseCallback() | ||
| job?.cancel() | ||
| try { | ||
| if (::session.isInitialized) session.cancel() | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.