Skip to content

Commit 125f9ea

Browse files
committed
Added 0.8.0 migration guide
1 parent 200719c commit 125f9ea

File tree

2 files changed

+367
-0
lines changed

2 files changed

+367
-0
lines changed

docs/pages/kotlinx-rpc/rpc.tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
<toc-element topic="strict-mode.topic"/>
4141
<toc-element topic="versions.topic"/>
4242
<toc-element toc-title="Migration guides">
43+
<toc-element topic="0-8-0.topic"/>
4344
<toc-element topic="0-6-0.topic"/>
4445
<toc-element topic="0-5-0.topic"/>
4546
<toc-element topic="0-4-0.topic"/>
Lines changed: 366 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,366 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
- Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
4+
-->
5+
6+
<!DOCTYPE topic
7+
SYSTEM "https://resources.jetbrains.com/writerside/1.0/xhtml-entities.dtd">
8+
<topic xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
9+
xsi:noNamespaceSchemaLocation="https://resources.jetbrains.com/writerside/1.0/topic.v2.xsd"
10+
title="Migration to 0.8.0" id="0-8-0">
11+
12+
<p>
13+
Version <code>0.8.0</code> brings a lot of changes,
14+
mainly targeted to remove inherently broken functionality and simplify kRPC protocol where possible.
15+
This is reflected in the number of breaking changes and deprecations.
16+
</p>
17+
<p>
18+
This page aims to cover all such changes and associated migration instructions.
19+
</p>
20+
21+
<chapter title="Strict mode enforcement" id="strict-mode-enforcement">
22+
<p>
23+
Strict mode is now enforced and can't be disabled.
24+
See <a href="strict-mode.topic"/> for detailed migrations.
25+
</p>
26+
</chapter>
27+
28+
<chapter title="kRPC protocol changes" id="krpc-protocol-changes">
29+
<p>
30+
The following changes are reflected in the kRPC protocol on the wire:
31+
</p>
32+
<list>
33+
<li>
34+
<code>KrpcServer</code> doesn't send CANCELLATION_ACK messages anymore.
35+
</li>
36+
<li>
37+
<code>KrpcClient</code> sends REQUEST cancellation messages for every individually finished call,
38+
canceled or finished successfully
39+
</li>
40+
</list>
41+
<p>
42+
Though changes should not affect most users,
43+
for those who like to look at the wire it might be useful to know.
44+
</p>
45+
</chapter>
46+
47+
<chapter title="Behavioral changes" id="behavioral-changes">
48+
<p>
49+
Some changes in the behavior of kRPC clients and servers:
50+
</p>
51+
<list>
52+
<li>
53+
<p>
54+
Lifetime for client-side streams is changed.
55+
</p>
56+
<p>
57+
Previously, the stream scopes bounded client-side streams.
58+
However, stream scopes are completely removed now,
59+
so the client-side streams lifetime is now bound to the request's lifetime.
60+
This means that when the function returns, every client stream is closed.
61+
</p>
62+
</li>
63+
<li>
64+
<p>
65+
Serial format is now only constructed once per client.
66+
</p>
67+
<p>
68+
Previously, the serial format was constructed once per RPC call.
69+
The serial format can be passed using the <code>KrpcConfig</code>.
70+
And the builder code was executed once per every call.
71+
</p>
72+
<p>
73+
Now this behavior is removed.
74+
The serial format is constructed once per client.
75+
</p>
76+
</li>
77+
<li>
78+
<p>
79+
Services are now instantiated once per service type (Rpc FQ name)
80+
and not once per client-side instance.
81+
</p>
82+
<p>
83+
Services lost their CoroutineScopes (see <a href="0-8-0.topic#incompatible-api-changes"/>).
84+
That means that there are no individual lifetimes for each service instance now.
85+
Instead, now each service stub on a client is merely a proxy for function calls.
86+
And on the server side, the service implementation is instantiated once per service type.
87+
To control this behavior more granularly on the server, new <code>deregisterService</code>
88+
function is introduced.
89+
</p>
90+
<tip>
91+
For kRPC servers, the factory function for service instances is now executed once per service type:
92+
<code-block lang="kotlin">
93+
rpcServer.registerService&lt;MyService&gt; { MyServiceImpl() }
94+
</code-block>
95+
</tip>
96+
</li>
97+
<li>
98+
<p>
99+
Handshake is now cold.
100+
</p>
101+
<p>
102+
Previously, the handshake was executed on client creation.
103+
Now, the handshake is executed on the first RPC request.
104+
</p>
105+
</li>
106+
</list>
107+
</chapter>
108+
109+
<chapter title="Incompatible API changes" id="incompatible-api-changes">
110+
<list>
111+
<li>
112+
<p>
113+
<code>RpcClient.callServerStreaming</code> lost its default implementation:
114+
</p>
115+
116+
<compare type="top-bottom">
117+
<code-block lang="Kotlin">
118+
interface RpcClient {
119+
fun &lt;T&gt; callServerStreaming(call: RpcCall): Flow&lt;T&gt; {
120+
error("Not implemented")
121+
}
122+
}
123+
</code-block>
124+
<code-block lang="Kotlin">
125+
interface RpcClient {
126+
fun &lt;T&gt; callServerStreaming(call: RpcCall): Flow&lt;T&gt;
127+
}
128+
</code-block>
129+
</compare>
130+
</li>
131+
<li>
132+
<p>
133+
<code>@Rpc</code> services lost their CoroutineScope:
134+
</p>
135+
<compare type="top-bottom">
136+
<code-block lang="Kotlin">
137+
val service = client.withService&lt;MyService&gt;()
138+
assert(service is CoroutineScope) // OK
139+
</code-block>
140+
<code-block lang="Kotlin">
141+
val service = client.withService&lt;MyService&gt;()
142+
assert(service is CoroutineScope) // fail
143+
</code-block>
144+
</compare>
145+
</li>
146+
<li>
147+
<p>
148+
<code>RpcClient</code> lost its <code>CoroutineScope</code>:
149+
</p>
150+
<compare type="top-bottom">
151+
<code-block lang="Kotlin">
152+
interface RpcClient : CoroutineScope
153+
</code-block>
154+
<code-block lang="Kotlin">
155+
interface RpcClient
156+
</code-block>
157+
</compare>
158+
</li>
159+
<li>
160+
<p>
161+
<code>RpcServer</code> lost its <code>CoroutineScope</code>:
162+
</p>
163+
<compare type="top-bottom">
164+
<code-block lang="Kotlin">
165+
interface RpcServer : CoroutineScope
166+
</code-block>
167+
<code-block lang="Kotlin">
168+
interface RpcServer
169+
</code-block>
170+
</compare>
171+
</li>
172+
<li>
173+
<p>
174+
<code>RpcServer.registerService</code> <code>factory</code> parameter changes type
175+
from <code>(CoroutineContext) -> Service</code> to <code>() -> Service</code>:
176+
</p>
177+
<compare type="top-bottom">
178+
<code-block lang="Kotlin">
179+
interface RpcServer {
180+
fun &lt;@Rpc Service : Any&gt; registerService(
181+
serviceKClass: KClass&lt;Service&gt;,
182+
serviceFactory: (CoroutineContext) -&gt; Service,
183+
)
184+
}
185+
186+
inline fun &lt;@Rpc reified Service : Any&gt; RpcServer.registerService(
187+
noinline serviceFactory: (CoroutineContext) -&gt; Service,
188+
) {
189+
registerService(Service::class, serviceFactory)
190+
}
191+
</code-block>
192+
<code-block lang="Kotlin">
193+
interface RpcServer {
194+
fun &lt;@Rpc Service : Any&gt; registerService(
195+
serviceKClass: KClass&lt;Service&gt;,
196+
serviceFactory: () -&gt; Service,
197+
)
198+
}
199+
200+
inline fun &lt;@Rpc reified Service : Any&gt; RpcServer.registerService(
201+
noinline serviceFactory: () -&gt; Service,
202+
) {
203+
registerService(Service::class, serviceFactory)
204+
}
205+
</code-block>
206+
</compare>
207+
</li>
208+
<li>
209+
<p>
210+
<code>RpcServer.registerService</code> lost its <code>CoroutineContext</code> parameter:
211+
</p>
212+
<compare type="top-bottom">
213+
<code-block lang="Kotlin">
214+
interface RpcServer
215+
</code-block>
216+
<code-block lang="Kotlin">
217+
interface RpcServer {
218+
fun &lt;@Rpc Service : Any&gt; deregisterService(
219+
serviceKClass: KClass&lt;Service&gt;,
220+
)
221+
}
222+
</code-block>
223+
</compare>
224+
</li>
225+
<li>
226+
<p>
227+
For Ktor, <code>HttpClient.rpc</code> extension function is now non-suspendable.
228+
</p>
229+
</li>
230+
<li>
231+
<code>KtorRpcClient.webSocketSession</code> is now wrapped in Deferred:
232+
<compare type="top-bottom">
233+
<code-block lang="Kotlin">
234+
interface KtorRpcClient : RpcClient {
235+
val webSocketSession: WebSocketSession
236+
}
237+
</code-block>
238+
<code-block lang="Kotlin">
239+
interface KtorRpcClient : RpcClient {
240+
val webSocketSession: Deferred&lt;WebSocketSession&gt;
241+
}
242+
</code-block>
243+
</compare>
244+
</li>
245+
<li>
246+
<p>
247+
<code>KrpcClient</code> abstract class has two new abstract methods:
248+
<code>initializeConfig</code> and <code>initializeTransport</code>.
249+
They can be used to delay transport initialization until the first RPC call.
250+
</p>
251+
<p>
252+
To mimic old behavior, <code>InitializedKrpcClient</code> can be used:
253+
</p>
254+
<compare type="top-bottom">
255+
<code-block lang="Kotlin">
256+
class MyClient(
257+
config: KrpcConfig,
258+
transport: KrpcTransport,
259+
) : KrpcClient(config, transport)
260+
</code-block>
261+
<code-block lang="Kotlin">
262+
class MyClient(
263+
config: KrpcConfig,
264+
transport: KrpcTransport,
265+
) : InitializedKrpcClient(transport, config)
266+
</code-block>
267+
</compare>
268+
<note>
269+
Notice that the parameter order is reversed in new <code>InitializedKrpcClient</code>.
270+
</note>
271+
</li>
272+
</list>
273+
</chapter>
274+
275+
<chapter title="API removals" id="api-removals">
276+
<p>
277+
The following APIs are removed:
278+
</p>
279+
<list>
280+
<li><code>kotlinx.rpc.RpcClient.callAsync</code> - previously deprecated</li>
281+
<li><code>kotlinx.rpc.RpcClient.provideStubContext</code></li>
282+
283+
<li><code>kotlinx.rpc.registerPlainFlowField</code> - previously deprecated</li>
284+
<li><code>kotlinx.rpc.registerSharedFlowField</code> - previously deprecated</li>
285+
<li><code>kotlinx.rpc.registerStateFlowField</code> - previously deprecated</li>
286+
<li><code>kotlinx.rpc.awaitFieldInitialization</code> - previously deprecated</li>
287+
<li><code>kotlinx.rpc.UninitializedRpcFieldException</code> - previously deprecated</li>
288+
<li><code>kotlinx.rpc.UninitializedRPCFieldException</code> - previously deprecated</li>
289+
<li><code>kotlinx.rpc.RpcEagerField</code> - previously deprecated</li>
290+
<li><code>kotlinx.rpc.RPCCall</code> - previously deprecated alias</li>
291+
<li><code>kotlinx.rpc.RPCClient</code> - previously deprecated alias</li>
292+
293+
<li><code>kotlinx.rpc.descriptor.RpcInvokator.Field</code> - previously deprecated</li>
294+
<li><code>kotlinx.rpc.descriptor.RpcServiceDescriptor.getFields</code> - previously deprecated</li>
295+
296+
<li><code>kotlinx.rpc.krpc.StreamScope</code> - previously deprecated</li>
297+
<li><code>kotlinx.rpc.krpc.streamScoped</code> - previously deprecated</li>
298+
<li><code>kotlinx.rpc.krpc.withStreamScope</code> - previously deprecated</li>
299+
<li><code>kotlinx.rpc.krpc.invokeOnStreamScopeCompletion</code> - previously deprecated</li>
300+
<li><code>kotlinx.rpc.krpc.KrpcConfigBuilder.SharedFlowParametersBuilder</code> - previously deprecated</li>
301+
<li><code>kotlinx.rpc.krpc.KrpcConfigBuilder.sharedFlowParameters</code> - previously deprecated</li>
302+
<li><code>kotlinx.rpc.krpc.KrpcConfig.sharedFlowBuilder</code> - previously deprecated</li>
303+
<li><code>kotlinx.rpc.krpc.RPCTransport</code> - previously deprecated alias</li>
304+
<li><code>kotlinx.rpc.krpc.RPCTransportMessage</code> - previously deprecated alias</li>
305+
<li><code>kotlinx.rpc.krpc.RPCConfigBuilder</code> - previously deprecated alias</li>
306+
<li><code>kotlinx.rpc.krpc.client.KRPCClient</code> - previously deprecated alias</li>
307+
<li><code>kotlinx.rpc.krpc.server.RPCServer</code> - previously deprecated alias</li>
308+
<li><code>kotlinx.rpc.krpc.server.KRPCServer</code> - previously deprecated alias</li>
309+
<li><code>kotlinx.rpc.krpc.serialization.RPCSerialFormat</code> - previously deprecated alias</li>
310+
<li><code>kotlinx.rpc.krpc.serialization.RPCSerialFormatBuilder</code> - previously deprecated alias</li>
311+
<li><code>kotlinx.rpc.krpc.serialization.RPCSerialFormatConfiguration</code> - previously deprecated alias</li>
312+
<li><code>kotlinx.rpc.krpc.ktor.client.RPC</code> - previously deprecated alias</li>
313+
<li><code>kotlinx.rpc.krpc.ktor.client.installRPC</code> - previously deprecated alias</li>
314+
<li><code>kotlinx.rpc.krpc.ktor.server.RPC</code> - previously deprecated alias</li>
315+
<li><code>kotlinx.rpc.krpc.ktor.server.RPCRoute</code> - previously deprecated alias</li>
316+
</list>
317+
</chapter>
318+
319+
<chapter title="Deprecations" id="deprecations">
320+
<list>
321+
<li>
322+
<p>
323+
Gradle's <code>rpc.strict</code> extension is deprecated with an error.
324+
Strict mode is now enforced and can't be disabled.
325+
See <a href="strict-mode.topic"/> for detailed migrations.
326+
</p>
327+
</li>
328+
<li>
329+
<p>
330+
<code>RemoteService</code> is deprecated with error;
331+
services are no longer having this interface added during the compilation.
332+
See <a href="0-8-0.topic#behavioral-changes"/> for services' lifetime information.
333+
</p>
334+
</li>
335+
</list>
336+
</chapter>
337+
338+
<chapter title="Other changes" id="other-changes">
339+
<list>
340+
<li>
341+
<p>
342+
<code>MISSING_RPC_ANNOTATION</code> compiler inspection is removed.
343+
</p>
344+
</li>
345+
<li>
346+
<p>
347+
ABI incompatible change: <code>KrpcTransport.receiveCatching</code> is now an extension function.
348+
</p>
349+
</li>
350+
<li>
351+
<p>
352+
The following compiler plugin options are removed:
353+
</p>
354+
<list>
355+
<li><code>strict-stateFlow</code></li>
356+
<li><code>strict-sharedFlow</code></li>
357+
<li><code>strict-nested-flow</code></li>
358+
<li><code>strict-stream-scope</code></li>
359+
<li><code>strict-suspending-server-streaming</code></li>
360+
<li><code>strict-not-top-level-server-flow</code></li>
361+
<li><code>strict-fields</code></li>
362+
</list>
363+
</li>
364+
</list>
365+
</chapter>
366+
</topic>

0 commit comments

Comments
 (0)