Skip to content

Commit 2ca42a7

Browse files
committed
chore: trace gRPC connection state changes; properly handle cancellation gRPC exceptions when backgrounding app
Signed-off-by: Brandon McAnsh <git@bmcreations.dev>
1 parent 98884eb commit 2ca42a7

5 files changed

Lines changed: 67 additions & 21 deletions

File tree

libs/logging/src/main/kotlin/com/getcode/utils/ErrorUtils.kt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,10 @@ object ErrorUtils {
3838
else throwable
3939

4040
if (throwableCause is StatusRuntimeException) {
41-
when (throwableCause.status) {
42-
Status.UNAVAILABLE -> return
43-
Status.CANCELLED -> return
41+
when (throwableCause.status.code) {
42+
Status.Code.UNAVAILABLE -> return
43+
Status.Code.CANCELLED -> return
44+
else -> { /* fall through */ }
4445
}
4546
}
4647

services/flipcash/src/main/kotlin/com/flipcash/services/inject/FlipcashModule.kt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ import dagger.Provides
4040
import dagger.hilt.InstallIn
4141
import dagger.hilt.android.qualifiers.ApplicationContext
4242
import dagger.hilt.components.SingletonComponent
43+
import com.getcode.utils.TraceType
44+
import com.getcode.utils.trace
45+
import io.grpc.ConnectivityState
4346
import io.grpc.ManagedChannel
4447
import io.grpc.android.AndroidChannelBuilder
4548
import io.grpc.okhttp.OkHttpChannelBuilder
@@ -87,6 +90,21 @@ internal object FlipcashModule {
8790
}
8891
}
8992
.build()
93+
.also { observeChannelState("flipcash", it) }
94+
}
95+
96+
private fun observeChannelState(name: String, channel: ManagedChannel) {
97+
val state = channel.getState(false)
98+
trace(
99+
tag = "gRPC",
100+
message = "$name => $state",
101+
type = TraceType.StateChange,
102+
)
103+
if (state != ConnectivityState.SHUTDOWN) {
104+
channel.notifyWhenStateChanged(state) {
105+
observeChannelState(name, channel)
106+
}
107+
}
90108
}
91109

92110
@Provides

services/opencode/src/main/kotlin/com/getcode/opencode/inject/OpenCodeModule.kt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ import dagger.Provides
4141
import dagger.hilt.InstallIn
4242
import dagger.hilt.android.qualifiers.ApplicationContext
4343
import dagger.hilt.components.SingletonComponent
44+
import com.getcode.utils.TraceType
45+
import com.getcode.utils.trace
46+
import io.grpc.ConnectivityState
4447
import io.grpc.ManagedChannel
4548
import io.grpc.android.AndroidChannelBuilder
4649
import io.grpc.okhttp.OkHttpChannelBuilder
@@ -101,6 +104,7 @@ object OpenCodeModule {
101104
}
102105
}
103106
.build()
107+
.also { observeChannelState("opencode", it) }
104108
}
105109

106110
@Singleton
@@ -122,6 +126,21 @@ object OpenCodeModule {
122126
}
123127
}
124128
.build()
129+
.also { observeChannelState("opencode-stream", it) }
130+
}
131+
132+
private fun observeChannelState(name: String, channel: ManagedChannel) {
133+
val state = channel.getState(false)
134+
trace(
135+
tag = "gRPC",
136+
message = "$name => $state",
137+
type = TraceType.StateChange,
138+
)
139+
if (state != ConnectivityState.SHUTDOWN) {
140+
channel.notifyWhenStateChanged(state) {
141+
observeChannelState(name, channel)
142+
}
143+
}
125144
}
126145

127146
@Provides

services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/core/GrpcApi.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ abstract class GrpcApi(protected val managedChannels: List<ManagedChannel>): Def
1414
ProcessLifecycleOwner.get().lifecycle.addObserver(this)
1515
}
1616

17-
1817
override fun onStart(owner: LifecycleOwner) {
1918
super.onStart(owner)
2019
warmUp()
@@ -23,4 +22,4 @@ abstract class GrpcApi(protected val managedChannels: List<ManagedChannel>): Def
2322
private fun warmUp() {
2423
managedChannels.onEach { it.enterIdle() }
2524
}
26-
}
25+
}

services/opencode/src/main/kotlin/com/getcode/opencode/utils/logging/LoggingClientCallListener.kt

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -22,22 +22,31 @@ class LoggingClientCallListener<ReqT, ResT>(
2222
val requestLog = requestQueue.joinToString(separator = ", ", prefix = "[", postfix = "]") { getObjectDetails(it) }
2323
val responseLog = responseQueue.joinToString(separator = ", ", prefix = "[", postfix = "]") { getObjectDetails(it) }
2424

25-
if (status.isOk) {
26-
trace(tag = "RpcLogging", message = "Request: $requestLog", type = TraceType.Network)
27-
trace(tag = "RpcLogging", message = "Response: $responseLog", type = TraceType.Network)
28-
trace(
29-
tag = "RpcLogging",
30-
message = "The request was processed successfully",
31-
type = TraceType.Network
32-
)
33-
} else {
34-
trace(tag = "RpcLogging", message = "Request: $requestLog", type = TraceType.Network)
35-
trace(
36-
tag = "RpcLogging",
37-
message = "An error occurred while processing the request",
38-
type = TraceType.Error,
39-
error = status.asRuntimeException(trailers)
40-
)
25+
trace(tag = "RpcLogging", message = "Request: $requestLog", type = TraceType.Network)
26+
when {
27+
status.isOk -> {
28+
trace(tag = "RpcLogging", message = "Response: $responseLog", type = TraceType.Network)
29+
trace(
30+
tag = "RpcLogging",
31+
message = "The request was processed successfully",
32+
type = TraceType.Network
33+
)
34+
}
35+
status.code == Status.Code.CANCELLED -> {
36+
trace(
37+
tag = "RpcLogging",
38+
message = "Request cancelled",
39+
type = TraceType.Log,
40+
)
41+
}
42+
else -> {
43+
trace(
44+
tag = "RpcLogging",
45+
message = "An error occurred while processing the request",
46+
type = TraceType.Error,
47+
error = status.asRuntimeException(trailers)
48+
)
49+
}
4150
}
4251

4352
super.onClose(status, trailers)

0 commit comments

Comments
 (0)