Skip to content

Commit bc8e338

Browse files
authored
Attach parent PluginResolver to plugin tracked coroutines (#4641)
1 parent 24120ed commit bc8e338

File tree

2 files changed

+36
-1
lines changed

2 files changed

+36
-1
lines changed

plugins/core/jetbrains-community/src/migration/software/aws/toolkits/jetbrains/core/coroutines/PluginCoroutineScopeTracker.kt

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,12 @@ import com.intellij.openapi.util.Disposer
1010
import kotlinx.coroutines.CoroutineName
1111
import kotlinx.coroutines.CoroutineScope
1212
import kotlinx.coroutines.SupervisorJob
13+
import kotlinx.coroutines.ThreadContextElement
1314
import kotlinx.coroutines.cancel
1415
import software.aws.toolkits.jetbrains.core.coroutines.getCoroutineBgContext
16+
import software.aws.toolkits.jetbrains.services.telemetry.PluginResolver
1517
import java.util.concurrent.CancellationException
18+
import kotlin.coroutines.CoroutineContext
1619

1720
class PluginCoroutineScopeTracker : Disposable {
1821
@PublishedApi
@@ -27,11 +30,30 @@ class PluginCoroutineScopeTracker : Disposable {
2730
}
2831

2932
private class BackgroundThreadPoolScope(coroutineName: String, disposable: Disposable) : CoroutineScope {
30-
override val coroutineContext = SupervisorJob() + CoroutineName(coroutineName) + getCoroutineBgContext()
33+
override val coroutineContext = SupervisorJob() +
34+
CoroutineName(coroutineName) +
35+
getCoroutineBgContext() +
36+
PluginResolverThreadContextElement(PluginResolver.fromCurrentThread())
3137

3238
init {
3339
Disposer.register(disposable) {
3440
coroutineContext.cancel(CancellationException("Parent disposable was disposed"))
3541
}
3642
}
3743
}
44+
45+
private class PluginResolverThreadContextElement(val pluginResolver: PluginResolver) : ThreadContextElement<PluginResolver> {
46+
companion object Key : CoroutineContext.Key<PluginResolverThreadContextElement>
47+
48+
override val key = Key
49+
50+
override fun updateThreadContext(context: CoroutineContext): PluginResolver {
51+
val oldPluginResolver = PluginResolver.fromCurrentThread()
52+
PluginResolver.setThreadLocal(pluginResolver)
53+
return oldPluginResolver
54+
}
55+
56+
override fun restoreThreadContext(context: CoroutineContext, oldState: PluginResolver) {
57+
PluginResolver.setThreadLocal(oldState)
58+
}
59+
}

plugins/core/jetbrains-community/tst/software/aws/toolkits/jetbrains/core/coroutines/ScopeTest.kt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import org.junit.Rule
2828
import org.junit.Test
2929
import org.junit.rules.TemporaryFolder
3030
import org.junit.rules.TestName
31+
import software.aws.toolkits.jetbrains.services.telemetry.PluginResolver
3132
import software.aws.toolkits.jetbrains.utils.isInstanceOf
3233
import java.time.Duration
3334
import java.util.concurrent.CancellationException
@@ -153,6 +154,18 @@ class ScopeTest {
153154
assertThatThrownBy { disposableCoroutineScope(ApplicationManager.getApplication()) }.isInstanceOf<IllegalStateException>()
154155
}
155156

157+
@Test
158+
fun `coroutine inherits PluginResolver from parent`() {
159+
val pluginResolver = PluginResolver.fromCurrentThread()
160+
PluginResolver.setThreadLocal(pluginResolver)
161+
162+
runBlocking {
163+
withContext(applicationCoroutineScope().coroutineContext) {
164+
assertThat(PluginResolver.fromCurrentThread()).isEqualTo(pluginResolver)
165+
}
166+
}
167+
}
168+
156169
private fun createFakePluginScope(componentManager: ComponentManager = ApplicationManager.getApplication()): Disposable {
157170
// We can't unload the real plugin in tests, so make another instance of the service and replace it for the tests
158171
val tracker = PluginCoroutineScopeTracker()

0 commit comments

Comments
 (0)