Cats-effect: [1.0.0-RC3] StackOverflowError

Created on 21 Aug 2018  Â·  5Comments  Â·  Source: typelevel/cats-effect

I've upgraded to RC3, and my program (a long process on more than 1M files) now fail very quickly with :

java.lang.StackOverflowError
    at cats.effect.internals.IORunLoop$.cats$effect$internals$IORunLoop$$loop(IORunLoop.scala:137)
    at cats.effect.internals.IORunLoop$RestartCallback.signal(IORunLoop.scala:336)
    at cats.effect.internals.IORunLoop$RestartCallback.apply(IORunLoop.scala:357)
    at cats.effect.internals.IORunLoop$RestartCallback.apply(IORunLoop.scala:303)
    at cats.effect.internals.IORunLoop$.cats$effect$internals$IORunLoop$$loop(IORunLoop.scala:134)
    at cats.effect.internals.IORunLoop$.startCancelable(IORunLoop.scala:41)
    at cats.effect.internals.IOBracket$.$anonfun$apply$2(IOBracket.scala:46)
    at cats.effect.internals.IOBracket$.$anonfun$apply$2$adapted(IOBracket.scala:35)
    at cats.effect.internals.IORunLoop$.cats$effect$internals$IORunLoop$$loop(IORunLoop.scala:134)
    at cats.effect.internals.IORunLoop$.start(IORunLoop.scala:34)
    at cats.effect.internals.IOBracket$.$anonfun$apply$1(IOBracket.scala:35)
    at cats.effect.internals.IOBracket$.$anonfun$apply$1$adapted(IOBracket.scala:32)
    at cats.effect.internals.IORunLoop$RestartCallback.start(IORunLoop.scala:328)
    at cats.effect.internals.IORunLoop$.cats$effect$internals$IORunLoop$$loop(IORunLoop.scala:117)
    at cats.effect.internals.IORunLoop$RestartCallback.signal(IORunLoop.scala:336)
    at cats.effect.internals.IORunLoop$RestartCallback.apply(IORunLoop.scala:357)
    at cats.effect.internals.IORunLoop$RestartCallback.apply(IORunLoop.scala:303)
    at cats.effect.internals.IORunLoop$.cats$effect$internals$IORunLoop$$loop(IORunLoop.scala:134)
    ...

I use only 2 bracket() (with better.files API, and F[_] : Sync executed with IO):

  private def writeGz(s: String, f: File): F[Unit] =
    F.bracket(F.delay(f.createIfNotExists(createParents = true).newOutputStream.asGzipOutputStream()))(out => F.delay(out.write(s.getBytes)).void)(out => F.delay(out.close()))

  private def readGZ(f: File): F[List[String]] =
    F.bracket(F.delay(f.newInputStream.asGzipInputStream()))(is => F.delay(is.lines.toList))(is => F.delay(is.close()))

I also use lot of F.delay(), some Timer.sleep() and some F.raiseError().

I will try to extract a minimal failing case later...

bug

Most helpful comment

@alexandru My program is running since 1 hour with 1.0.0-RC3-3e17307. I think it's OK.
Thank you.

All 5 comments

Oops, I'm fixing it — sorry about that, 1.0.0 should happen on Sep 3, so it's not a long wait.

The problem is in IO's implementation. You can translate something like this:

IO(acquire).bracket(use)(release)

Into this:

IO(acquire).bracket(a => IO.cancelBoundary *> use(a))(release)

IO.cancelBoundary behaves like a lighter shift; so you can do this too:

IO(acquire).bracket(a => IO.shift *> use(a))(release)

Unfortunately for polymorphic code this would require Async instead of Sync.

Fixed in PR #317.

@ronanM I published 1.0.0-RC3-3e17307, synchronizing on Maven Central.

You can depend on this version for now and I'd appreciate if you double checked if the fix worked for you. It's API compatible with 1.0.0-RC3, a drop-in replacement.

I'm re-opening the issue until we get confirmation.

@alexandru My program is running since 1 hour with 1.0.0-RC3-3e17307. I think it's OK.
Thank you.

Thanks for confirming @ronanM. Closing.

Was this page helpful?
0 / 5 - 0 ratings