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...
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.
Most helpful comment
@alexandru My program is running since 1 hour with
1.0.0-RC3-3e17307. I think it's OK.Thank you.