fs2 - Recurring stream that recovers upon an error

Viewed 94

I'm trying to create a fs2 stream that,

  • Evaluates a function every 3 seconds and save that data into a file
  • Upon an error, try to authenticate and restart the same stream
  • Interrupts based on a separate stream when necessary

Below is my approach but I'm not sure whether its the best way to do so.
I've used uppercase for the function name to highlight the place that it gets called.

private def CREATE_STREAM_RECURSIVE(
     session: AuthSession,
     myService: MyService[IO],
     sessionStore: SessionStore[IO],
  ): Stream[IO, Unit] = {
    Stream
      .repeatEval(service.fetchData(session))
      .flatMap { data =>
        val jsonStream = Stream.eval(IO.delay(data.asJson.noSpaces))
        persistToFile(jsonStream) <-- another fs2 stream that writes to a file
      }
      .metered(3.seconds)
      .handleErrorWith { _ =>
        Stream.force {
          myService.login()
            .flatMap(sessionStore.setSession)
            .map(CREATE_STREAM_RECURSIVE(_, myService, sessionStore)) //recursive
        }
      }
      .interruptWhen(isItOkToInterruptStream)
  }

Questions:

  • If an error keeps happening, is it possible for this recursion to blow the stack?
  • When the interruption happens, is it possible for this stream to stop without completing the file write?
  • If so, is there anyway to ensure that the file is written completely before the exit happens?

Thanks

1 Answers

With help from SystemFw, I was able to find out answers through fs2 discord channel.

If an error keeps happening, is it possible for this recursion to blow the stack?

No, because that recursion is monadic and it goes through a flatMap, which in this case is hidden by force, and therefore it's stack safe

When the interruption happens, is it possible for this stream to stop without completing the file write?

Yes

If so, is there anyway to ensure that the file is written completely before the exit happens?

Yes, by making file write uninterruptible by transforming it into an IO and calling .uncancelable on it

Related