Skip to content

Instantly share code, notes, and snippets.

@erikvanoosten
Created April 8, 2023 05:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save erikvanoosten/c63b037f1b1e375b45e929972e4aef2a to your computer and use it in GitHub Desktop.
Save erikvanoosten/c63b037f1b1e375b45e929972e4aef2a to your computer and use it in GitHub Desktop.
Reproduces problem where a ZIO taks runs on another thread than expected
import zio.internal.ExecutionMetrics
import zio.{Executor, Runtime, RuntimeFlag, RuntimeFlags, Scope, Task, Trace, Unsafe, ZIO, ZIOAppArgs, ZIOAppDefault, ZLayer}
object RuntimeReproducer extends ZIOAppDefault {
override def run: ZIO[Any with ZIOAppArgs with Scope, Any, Any] =
for {
runtime <- ZIO.runtime[Any]
_ <- ZIO.attempt {
println("main thread id" + Thread.currentThread().getId)
unsafeRunOnThisThread(runtime) {
ZIO.attempt {
println("other thread id" + Thread.currentThread().getId)
}
}
()
}
} yield ()
// Prints:
// main thread id15
// other thread id13
def unsafeRunOnThisThread(runtime: Runtime[Any])(task: Task[Unit]): Unit =
Unsafe.unsafe { implicit u =>
runtime.unsafe
.run(
task.provideLayer(SameThreadRuntimeLayer)
)
.getOrThrowFiberFailure()
()
}
private def disableCooperativeYielding(implicit trace: Trace): ZLayer[Any, Nothing, Unit] =
ZLayer.scoped {
ZIO.withRuntimeFlagsScoped(RuntimeFlags.disable(RuntimeFlag.CooperativeYielding))
}
private val SameThreadRuntimeLayer: ZLayer[Any, Nothing, Unit] = {
val sameThreadExecutor = new Executor() {
override def metrics(implicit unsafe: Unsafe): Option[ExecutionMetrics] = None
override def submit(runnable: Runnable)(implicit unsafe: Unsafe): Boolean = {
runnable.run()
true
}
}
Runtime.setExecutor(sameThreadExecutor) ++
Runtime.setBlockingExecutor(sameThreadExecutor) ++
disableCooperativeYielding
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment