Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deadlock with toEffect #694

Open
steinybot opened this issue Jul 24, 2024 · 8 comments
Open

Deadlock with toEffect #694

steinybot opened this issue Jul 24, 2024 · 8 comments

Comments

@steinybot
Copy link

steinybot commented Jul 24, 2024

cats-effect 3.5.4, fs2 3.10.2, and interop-cats 23.1.0.2 and Scala 2.13

This will hang:

package com.goodcover

import cats.effect.IO
import cats.effect.unsafe.IORuntime
import com.typesafe.scalalogging.StrictLogging
import org.scalatest.flatspec.AnyFlatSpec
import zio.ZIO
import zio.interop._
import zio.interop.catz.implicits._

final class IOSpec extends AnyFlatSpec with StrictLogging {

  behavior of "ZIO to IO"

  it should "not deadlock" in {
    var count = 0
    while (!Thread.interrupted()) {
      count += 1
      logger.debug("Running test " + count)
      ZIO.succeed(()).toEffect[IO].unsafeRunSync()(IORuntime.global)
    }
  }
}
@steinybot
Copy link
Author

What's weird is that there are no live cats fibers when it deadlocks.

@steinybot steinybot changed the title Deadlock with toEffect and fs2 Deadlock with toEffect Jul 24, 2024
@steinybot
Copy link
Author

steinybot commented Jul 24, 2024

This problem looks more fundamental. Something wrong with fiber observers.

This also hangs:

package com.goodcover

import com.typesafe.scalalogging.StrictLogging
import org.scalatest.flatspec.AnyFlatSpec
import zio.interop._
import zio.interop.catz.implicits._
import zio.{Unsafe, ZIO}

import java.util.concurrent.CountDownLatch

final class ZSpec extends AnyFlatSpec with StrictLogging {

  behavior of "ZIO to IO"

  it should "not deadlock" in {
    var count = 0
    while (!Thread.interrupted() && count < 100_000) {
      count += 1
      logger.debug("Running test " + count)
      val done = new CountDownLatch(1)
      Unsafe.unsafe { implicit unsafe =>
        val fiber = rts.unsafe.fork(ZIO.succeed(()))
        fiber.unsafe.addObserver { exit =>
          logger.debug(s"Done: $exit")
          done.countDown()
        }
      }
      done.await()
    }
  }
}

@steinybot
Copy link
Author

Ahh I think the fiber is completing before the call to addObserver happens and it doesn't handle that case.

@steinybot
Copy link
Author

Nope that's not it. It does handle that. However observers is not volatile so there is no happens-before relationship. I bet that is it.

@steinybot
Copy link
Author

Caused by zio/zio#9040

@steinybot steinybot closed this as not planned Won't fix, can't repro, duplicate, stale Jul 25, 2024
@steinybot steinybot reopened this Jul 25, 2024
@steinybot
Copy link
Author

Actually reopening this so as to ensure this is updated on release and/or worked around.

I think a workaround is possible using onExit rather than a fiber observer.

@calvinlfer
Copy link
Member

hey @steinybot is this still happening with the issue in core being fixed?

@steinybot
Copy link
Author

We tried the snapshot build and it fixed it so I assume it is fixed. I've just updated to 2.1.7 so will see if it is still gone.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants