Skip to content

Commit 1955a9e

Browse files
authored
refactor: log coroutine errors (#805)
* refactor: log coroutine errors * refactor: log coroutine errors * style: detekt * style: detekt
1 parent a42af7d commit 1955a9e

File tree

26 files changed

+186
-140
lines changed

26 files changed

+186
-140
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
* Source++, the open-source live coding platform.
3+
* Copyright (C) 2022 CodeBrig, Inc.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package spp.jetbrains
18+
19+
import com.intellij.openapi.diagnostic.logger
20+
import io.vertx.core.Vertx
21+
import io.vertx.kotlin.coroutines.dispatcher
22+
import kotlinx.coroutines.*
23+
24+
object ScopeExtensions {
25+
26+
private val log = logger<ScopeExtensions>()
27+
28+
fun <T> safeRunBlocking(action: suspend () -> T): T {
29+
return runBlocking {
30+
try {
31+
return@runBlocking action()
32+
} catch (throwable: Throwable) {
33+
log.error(throwable)
34+
throw throwable
35+
}
36+
}
37+
}
38+
39+
suspend fun safeExecute(action: suspend () -> Unit) {
40+
try {
41+
action()
42+
} catch (throwable: Throwable) {
43+
log.error(throwable)
44+
}
45+
}
46+
47+
fun safeGlobalLaunch(action: suspend () -> Unit) {
48+
GlobalScope.launch {
49+
safeExecute {
50+
action()
51+
}
52+
}
53+
}
54+
55+
fun safeGlobalAsync(
56+
action: suspend CoroutineScope.() -> Unit
57+
): Deferred<*> {
58+
return GlobalScope.async {
59+
safeExecute {
60+
action()
61+
}
62+
}
63+
}
64+
}
65+
66+
fun Vertx.safeLaunch(action: suspend () -> Unit): Job {
67+
return GlobalScope.launch(dispatcher()) {
68+
ScopeExtensions.safeExecute {
69+
action()
70+
}
71+
}
72+
}

core/src/main/kotlin/spp/jetbrains/command/LiveCommand.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ package spp.jetbrains.command
1919
import com.intellij.openapi.application.ApplicationManager
2020
import com.intellij.openapi.project.Project
2121
import com.intellij.psi.PsiElement
22-
import kotlinx.coroutines.runBlocking
22+
import spp.jetbrains.ScopeExtensions.safeRunBlocking
2323
import spp.jetbrains.UserData
2424
import spp.jetbrains.plugin.LiveStatusManager
2525
import spp.protocol.platform.developer.SelfInfo
@@ -43,7 +43,7 @@ abstract class LiveCommand(val project: Project) {
4343

4444
open fun trigger(context: LiveCommandContext) {
4545
ApplicationManager.getApplication().runReadAction {
46-
runBlocking {
46+
safeRunBlocking {
4747
triggerSuspend(context)
4848
}
4949
}

core/src/main/kotlin/spp/jetbrains/indicator/LiveIndicator.kt

+4-6
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,11 @@ package spp.jetbrains.indicator
1919
import com.apollographql.apollo3.exception.ApolloException
2020
import com.intellij.openapi.diagnostic.logger
2121
import com.intellij.openapi.project.Project
22-
import io.vertx.kotlin.coroutines.dispatcher
23-
import kotlinx.coroutines.GlobalScope
24-
import kotlinx.coroutines.launch
22+
import spp.jetbrains.UserData
23+
import spp.jetbrains.safeLaunch
2524
import spp.jetbrains.marker.source.mark.api.event.IEventCode
2625
import spp.jetbrains.marker.source.mark.api.event.SourceMarkEvent
2726
import spp.jetbrains.marker.source.mark.guide.GuideMark
28-
import spp.jetbrains.UserData
2927
import spp.jetbrains.status.SourceStatus.ConnectionError
3028
import spp.jetbrains.status.SourceStatus.Ready
3129
import spp.jetbrains.status.SourceStatusService
@@ -48,10 +46,10 @@ abstract class LiveIndicator(val project: Project) {
4846
open suspend fun onRegister() {
4947
vertx.setPeriodic(5000) { timerId ->
5048
periodicTimerId = timerId
51-
GlobalScope.launch(vertx.dispatcher()) {
49+
vertx.safeLaunch {
5250
if (SourceStatusService.getInstance(project).getCurrentStatus().first != Ready) {
5351
log.debug("Not ready, ignoring indicator refresh")
54-
return@launch
52+
return@safeLaunch
5553
}
5654

5755
try {

core/src/main/kotlin/spp/jetbrains/plugin/impl/LivePluginServiceImpl.kt

+5-7
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import com.apollographql.apollo3.exception.ApolloNetworkException
2020
import com.intellij.openapi.diagnostic.logger
2121
import com.intellij.openapi.project.Project
2222
import com.intellij.psi.PsiElement
23-
import kotlinx.coroutines.runBlocking
23+
import spp.jetbrains.ScopeExtensions.safeRunBlocking
2424
import spp.jetbrains.command.LiveCommand
2525
import spp.jetbrains.indicator.LiveIndicator
2626
import spp.jetbrains.marker.SourceMarker
@@ -58,22 +58,20 @@ class LivePluginServiceImpl(val project: Project) : LivePluginService {
5858
override fun registerLiveIndicator(indicator: LiveIndicator) {
5959
val eventListener = SourceMarkEventListener {
6060
if ((indicator.listenForAllEvents || indicator.listenForEvents.contains(it.eventCode)) && it.sourceMark is GuideMark) {
61-
runBlocking {
61+
safeRunBlocking {
6262
try {
6363
indicator.trigger(it.sourceMark as GuideMark, it)
6464
} catch (e: ApolloNetworkException) {
65-
log.warn("Error while triggering indicator $indicator", e)
65+
log.warn("Network error while triggering indicator $indicator", e)
6666
SourceStatusService.getInstance(project).update(ConnectionError, e.message)
67-
} catch (e: Exception) {
68-
log.warn("Error while triggering indicator $indicator", e)
6967
}
7068
}
7169
}
7270
}
7371
SourceMarker.getInstance(project).addGlobalSourceMarkEventListener(eventListener)
7472
indicators[indicator] = eventListener
7573

76-
runBlocking {
74+
safeRunBlocking {
7775
indicator.onRegister()
7876
}
7977
log.debug("Registered indicator: $indicator - Current indicators: ${indicators.size}")
@@ -88,7 +86,7 @@ class LivePluginServiceImpl(val project: Project) : LivePluginService {
8886
SourceMarker.getInstance(project).removeGlobalSourceMarkEventListener(it.value)
8987
indicators.remove(it.key)
9088

91-
runBlocking {
89+
safeRunBlocking {
9290
indicator.onUnregister()
9391
}
9492
log.debug("Unregistered indicator: $indicator - Current indicators: ${indicators.size}")

marker/jvm-marker/build.gradle.kts

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ intellij {
1212
}
1313

1414
dependencies {
15+
compileOnly(projectDependency(":common"))
1516
compileOnly(projectDependency(":marker"))
1617
compileOnly("plus.sourceplus:protocol:$projectVersion")
1718

marker/jvm-marker/src/main/kotlin/spp/jetbrains/marker/jvm/ArtifactSearch.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@ import com.intellij.psi.search.ProjectScope
2727
import io.vertx.core.Promise
2828
import io.vertx.core.Vertx
2929
import io.vertx.kotlin.coroutines.await
30-
import kotlinx.coroutines.runBlocking
3130
import org.jetbrains.uast.UMethod
3231
import org.jetbrains.uast.toUElement
3332
import org.jetbrains.uast.toUElementOfType
33+
import spp.jetbrains.ScopeExtensions.safeRunBlocking
3434
import spp.jetbrains.marker.source.JVMMarkerUtils
3535
import spp.protocol.artifact.ArtifactNameUtils
3636
import spp.protocol.artifact.ArtifactQualifiedName
@@ -138,7 +138,7 @@ object ArtifactSearch {
138138
file.accept(object : PsiRecursiveElementVisitor(true) {
139139
override fun visitElement(element: PsiElement) {
140140
if (element is PsiMethod) {
141-
runBlocking {
141+
safeRunBlocking {
142142
val endpointName =
143143
endpointDetector.determineEndpointName(element.toUElementOfType()!!).await()
144144
if (endpointName.isPresent && endpointName.get().name == artifact.identifier) {

marker/jvm-marker/src/main/kotlin/spp/jetbrains/marker/jvm/psi/LoggerDetector.kt

+4-6
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,10 @@ import io.vertx.core.Future
2828
import io.vertx.core.Promise
2929
import io.vertx.core.Vertx
3030
import io.vertx.kotlin.coroutines.await
31-
import io.vertx.kotlin.coroutines.dispatcher
32-
import kotlinx.coroutines.GlobalScope
33-
import kotlinx.coroutines.launch
34-
import kotlinx.coroutines.runBlocking
3531
import org.jetbrains.uast.UMethod
3632
import org.jetbrains.uast.toUElementOfType
33+
import spp.jetbrains.ScopeExtensions.safeRunBlocking
34+
import spp.jetbrains.safeLaunch
3735
import spp.jetbrains.marker.source.SourceFileMarker
3836
import spp.jetbrains.marker.source.mark.api.MethodSourceMark
3937
import spp.jetbrains.marker.source.mark.api.key.SourceKey
@@ -66,7 +64,7 @@ class LoggerDetector(val vertx: Vertx) {
6664
ApplicationManager.getApplication().runReadAction {
6765
val methodSourceMark = findMethodSourceMark(editor, inlayMark.sourceFileMarker, lineLocation)
6866
if (methodSourceMark != null) {
69-
runBlocking {
67+
safeRunBlocking {
7068
getOrFindLoggerStatements(methodSourceMark)
7169
}
7270
val loggerStatements = methodSourceMark.getUserData(LOGGER_STATEMENTS)!! as MutableList<DetectedLogger>
@@ -104,7 +102,7 @@ class LoggerDetector(val vertx: Vertx) {
104102

105103
fun getOrFindLoggerStatements(uMethod: UMethod): Future<List<DetectedLogger>> {
106104
val promise = Promise.promise<List<DetectedLogger>>()
107-
GlobalScope.launch(vertx.dispatcher()) {
105+
vertx.safeLaunch {
108106
val loggerStatements = mutableListOf<DetectedLogger>()
109107
try {
110108
loggerStatements.addAll(determineLoggerStatements(uMethod).await())

marker/src/main/kotlin/spp/jetbrains/marker/SourceMarker.kt

+2-3
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,7 @@ import com.intellij.openapi.diagnostic.logger
2323
import com.intellij.openapi.project.Project
2424
import com.intellij.openapi.util.Key
2525
import com.intellij.psi.PsiFile
26-
import kotlinx.coroutines.GlobalScope
27-
import kotlinx.coroutines.launch
26+
import spp.jetbrains.ScopeExtensions.safeGlobalLaunch
2827
import spp.jetbrains.marker.impl.ArtifactNamingService
2928
import spp.jetbrains.marker.impl.SourceGuideProvider
3029
import spp.jetbrains.marker.source.SourceFileMarker
@@ -101,7 +100,7 @@ class SourceMarker {
101100
fileMarker = availableSourceFileMarkers[psiFile.hashCode()]!!
102101
psiFile.putUserData(SourceFileMarker.KEY, fileMarker)
103102

104-
GlobalScope.launch {
103+
safeGlobalLaunch {
105104
SourceGuideProvider.determineGuideMarks(fileMarker)
106105
}
107106
return fileMarker

marker/src/main/kotlin/spp/jetbrains/marker/plugin/FileActivityListener.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ import com.intellij.openapi.project.DumbService
3030
import com.intellij.openapi.vfs.VirtualFile
3131
import com.intellij.psi.PsiFile
3232
import com.intellij.psi.PsiManager
33-
import kotlinx.coroutines.runBlocking
33+
import spp.jetbrains.ScopeExtensions.safeRunBlocking
3434
import spp.jetbrains.marker.SourceMarker
3535
import spp.jetbrains.marker.source.SourceFileMarker
3636
import spp.jetbrains.marker.source.mark.gutter.GutterMark
@@ -60,7 +60,7 @@ class FileActivityListener : FileEditorManagerListener {
6060
val psiFile = PsiManager.getInstance(source.project).findFile(file)
6161
val fileMarker = psiFile?.getUserData(SourceFileMarker.KEY)
6262
if (fileMarker != null) {
63-
runBlocking {
63+
safeRunBlocking {
6464
SourceMarker.getInstance(source.project).deactivateSourceFileMarker(fileMarker)
6565
}
6666
}

marker/src/main/kotlin/spp/jetbrains/marker/source/SourceFileMarker.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import com.intellij.openapi.util.Key
2727
import com.intellij.psi.PsiElement
2828
import com.intellij.psi.PsiFile
2929
import com.intellij.psi.PsiNameIdentifierOwner
30-
import kotlinx.coroutines.runBlocking
30+
import spp.jetbrains.ScopeExtensions.safeRunBlocking
3131
import spp.jetbrains.marker.source.mark.api.*
3232
import spp.jetbrains.marker.source.mark.api.event.SourceMarkEvent
3333
import spp.jetbrains.marker.source.mark.api.event.SourceMarkEventCode
@@ -87,7 +87,7 @@ open class SourceFileMarker(val psiFile: PsiFile) : SourceMarkProvider {
8787

8888
open suspend fun clearSourceMarks() {
8989
val removed = sourceMarks.removeIf {
90-
runBlocking {
90+
safeRunBlocking {
9191
it.disposeSuspend(false)
9292
}
9393
true

marker/src/main/kotlin/spp/jetbrains/marker/source/info/EndpointDetector.kt

+3-9
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,13 @@ import com.intellij.openapi.project.Project
2222
import com.intellij.openapi.util.Key
2323
import io.vertx.core.Future
2424
import io.vertx.kotlin.coroutines.await
25-
import io.vertx.kotlin.coroutines.dispatcher
26-
import kotlinx.coroutines.GlobalScope
27-
import kotlinx.coroutines.launch
2825
import spp.jetbrains.UserData
2926
import spp.jetbrains.marker.SourceMarker
3027
import spp.jetbrains.marker.source.mark.api.key.SourceKey
3128
import spp.jetbrains.marker.source.mark.guide.GuideMark
3229
import spp.jetbrains.marker.source.mark.guide.MethodGuideMark
3330
import spp.jetbrains.monitor.skywalking.SkywalkingMonitorService
31+
import spp.jetbrains.safeLaunch
3432
import java.util.*
3533

3634
/**
@@ -66,12 +64,8 @@ abstract class EndpointDetector<T : EndpointDetector.EndpointNameDeterminer>(val
6664

6765
val vertx = UserData.vertx(project)
6866
vertx.setPeriodic(5000) {
69-
GlobalScope.launch(vertx.dispatcher()) {
70-
try {
71-
redetectEndpoints()
72-
} catch (e: Exception) {
73-
log.error("Error detecting endpoints", e)
74-
}
67+
vertx.safeLaunch {
68+
redetectEndpoints()
7569
}
7670
}
7771
}

marker/src/main/kotlin/spp/jetbrains/marker/source/mark/api/SourceMark.kt

+4-5
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,8 @@ import com.intellij.ui.BalloonImpl
3838
import com.intellij.ui.JBColor
3939
import com.intellij.ui.awt.RelativePoint
4040
import com.intellij.util.ui.JBUI
41-
import kotlinx.coroutines.GlobalScope
42-
import kotlinx.coroutines.launch
43-
import kotlinx.coroutines.runBlocking
41+
import spp.jetbrains.ScopeExtensions.safeGlobalLaunch
42+
import spp.jetbrains.ScopeExtensions.safeRunBlocking
4443
import spp.jetbrains.marker.SourceMarker
4544
import spp.jetbrains.marker.plugin.SourceInlayComponentProvider
4645
import spp.jetbrains.marker.plugin.SourceInlayHintProvider
@@ -276,7 +275,7 @@ interface SourceMark : JBPopupListener, MouseMotionListener, VisibleAreaListener
276275
.forEach { it.handleEvent(event) }
277276

278277
//async listeners
279-
GlobalScope.launch {
278+
safeGlobalLaunch {
280279
eventListeners.forEach {
281280
if (it !is SynchronousSourceMarkEventListener) {
282281
it.handleEvent(event)
@@ -293,7 +292,7 @@ interface SourceMark : JBPopupListener, MouseMotionListener, VisibleAreaListener
293292
.forEach { it.handleEvent(event) }
294293

295294
//async listeners
296-
runBlocking {
295+
safeRunBlocking {
297296
getEventListeners().forEach {
298297
if (it !is SynchronousSourceMarkEventListener) {
299298
it.handleEvent(event)

marker/src/main/kotlin/spp/jetbrains/marker/source/mark/api/component/jcef/SourceMarkJcefComponent.kt

+2-3
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,10 @@ import com.intellij.openapi.util.Disposer
2121
import com.intellij.ui.jcef.JBCefApp
2222
import com.intellij.ui.jcef.JBCefBrowser
2323
import com.intellij.ui.jcef.JBCefClient
24-
import kotlinx.coroutines.GlobalScope
2524
import kotlinx.coroutines.delay
26-
import kotlinx.coroutines.launch
2725
import org.joor.Reflect
2826
import org.joor.ReflectException
27+
import spp.jetbrains.ScopeExtensions.safeGlobalLaunch
2928
import spp.jetbrains.marker.source.mark.api.component.api.SourceMarkComponent
3029
import spp.jetbrains.marker.source.mark.api.component.jcef.config.SourceMarkJcefComponentConfiguration
3130
import java.awt.Dimension
@@ -68,7 +67,7 @@ class SourceMarkJcefComponent(
6867
browser = JBCefBrowser(client, configuration.initialUrl)
6968

7069
//periodically update zoom level
71-
GlobalScope.launch {
70+
safeGlobalLaunch {
7271
while (browser != null) {
7372
delay(50)
7473
try {

0 commit comments

Comments
 (0)