How to shutdown a fs2.StreamApp programmatically? - scala

Extending StreamApp asks you to provide the stream def. It has a requestShutdown parameter.
def stream(args: List[String], requestShutdown: F[Unit]): Stream[F, ExitCode]
I provide the implementation for this and understand that args is passed in as command line arguments. I'm unsure however, what supplies the requestShutdown parameter and what I can do with it.
Specifically, I'd like to invoke a graceful shutdown on a Stream[IO, ExitCode] which is starting a Http4s server (which blocks forever).
It looks like a Signal is needed and must be set? The underlying stream that I'm trying to 'get at' looks like this:
for {
scheduler <- Scheduler[IO](corePoolSize = 1)
exitCode <- BlazeBuilder[IO]
.bindHttp(port, "0.0.0.0")
.mountService(services(scheduler), "/")
.serve
} yield exitCode
My stream def is here and StreamAppSpec from the fs2 project has something in the StreamAppSpec but I can't work out how I'd adapt it.

You can think of the requestShutdown parameter that is supplied to the stream function as meaning an action that, when executed, will request the termination of the program.
Executing it will consequently result in it ending the program.
Here is an example use:
override def stream(args: List[String], requestShutdown: IO[Unit]): Stream[IO, ExitCode] =
for {
scheduler <- Scheduler[IO](corePoolSize = 1)
exitStream = scheduler.sleep[IO](10 seconds)
.evalMap(_ => requestShutdown)
.map(_ => ExitCode.Success)
serverStream = BlazeBuilder[IO]
.bindHttp(port, "0.0.0.0")
.mountService(services(scheduler), "/")
.serve
result <- Stream.emits(List(exitStream, serverStream)).joinUnbounded
} yield result
In this scenario, we create two streams:
The first will wait for 10 seconds before triggering the effect of
terminating the app.
The second will run the http4s server.
We then join these two streams so that they run concurrently meaning that the web server will run for 10 seconds before the other stream signals that the program should terminate.

Related

For Comprehension of Futures - Kicking off new thread inside comprehension and disregarding result

I'm trying to use a for comprehension to both run some futures in order and merged results, but also kick off a separate thread after one of those futures completes and not care about the result (basically used to fire some logging info)
I've played around a bit with this with some thread sleeps and it looks like whatever i'm throwing inside the for block will end up blocking the thread.
private def testFunction(): EitherT[Future, Error, Response] =
for {
firstRes <- EitherT(client.getFirst())
secondRes <- EitherT(client.getSecond())
// Future i want to run on a separate async thread outside the comprehension
_ = runSomeLogging(secondRes)
thirdRes <- EitherT(client.getThird(secondRes.value))
} yield thirdRes
def runSomeLogging(): Future[Either[Error, Response]] =
Thread.sleep(10000)
Future.successful(Right(Response("123")))
}
So this above code will wait the 10 seconds before returning the thirdRes result. My hope was to kick off the runSomeLogging function on a separate thread after the secondRes runs. I thought the usage of = rather than <- would cause that, however it doesn't.
The way I am able to get this to work is below. Basically I run my second future outside of the comprehension and use .onComplete on the previous future to only run my logging if certain conditions were meant from the above comprehension. I only want to run this logging function if the secondRes function is successful in my example here.
private def runSomeLogging(response: SecondRes) =
Thread.sleep(10000)
response.value.onComplete {
case Success(either) =>
either.fold(
_ => { },
response => { logThing() }
)
case _ =>
}
private def testFunction(): EitherT[Future, Error, Response] =
val res = for {
firstRes <- EitherT(client.getFirst())
secondRes <- EitherT(client.getSecond())
thirdRes <- EitherT(client.getThird(secondRes.value))
} yield thirdRes
runSomeLogging(res)
return res
This second example works fine and does what I want, it doesn't block the for comprehension for 10 seconds from returning. However, because there are dependencies of this running for certain pieces of the comprehension, but not all of them, I was hoping there was a way to kick off the job from within the for comprehension itself but let it run on its own thread and not block the comprehension from completing.
You need a function that starts the Future but doesn't return it, so the for-comprehension can move on (since Future's map/flatMap functions won't continue to the next step until the current Future resolves). To accomplish a "start and forget", you need to use a function that returns immediately, or a Future that resolves immediately.
// this function will return immediately
def runSomeLogging(res: SomeResult): Unit = {
// since startLoggingFuture uses Future.apply, calling it will start the Future,
// but we ignore the actual Future by returning Unit instead
startLoggingFuture(res)
}
// this function returns a future that takes 10 seconds to resolve
private def startLoggingFuture(res: SomeResult): Future[Unit] = Future {
// note: please don't actually do Thread.sleep in your Future's thread pool
Thread.sleep(10000)
logger.info(s"Got result $res")
}
Then you could put e.g.
_ = runSomeLogging(res)
or
_ <- Future { runSomeLogging(res) }
in your for-comprehension.
Note, Cats-Effect and Monix have a nice abstraction for "start but ignore result", with io.start.void and task.startAndForget respectively. If you were using IO or Task instead of Future, you could use .start.void or .startAndForget on the logging task.

Integration tests hangs when testing my API in ZIO + HTTP4S

I am having issues testing my first ZIO+HTTP4S application. The test hangs and does not finish.
The code for my App (simplified) is
object Main extends App {
def server: ZIO[AppEnvironment, Throwable, Unit] =
for {
(...)
fullApp <- ZIO.runtime[AppEnvironment].flatMap { implicit rts =>
BlazeServerBuilder[AppTask](ec)
.bindHttp(api.port, api.endpoint)
.withHttpApp(CORS(httpApp))
.serve
.compile[AppTask, AppTask, CatsExitCode]
.drain
}
} yield fullApp
override def run(args: List[String]): ZIO[ZEnv, Nothing, ExitCode] = {
server.provideSomeLayer[ZEnv](appEnvironment).tapError(err => putStrLn(s"Execution failed with: $err")).exitCode
}
}
This is my test code. Note that it is basically copypasted from THIS OTHER STACKOVERFLOW QUESTION
object ApiTest extends DefaultRunnableSpec {
val ec: ExecutionContext = ExecutionContext.global
def httpServer = Main.run(List()).forkManaged.toLayer
val clockDuration = ofSeconds(1)
val blocker = Blocker.liftExecutionContext(ec)
//did the httpserver start listening on 8080?
private def isLocalPortInUse(port: Int): ZIO[Clock, Throwable, Unit] = {
IO.effect {
println("checking for local port in use")
new Socket("0.0.0.0", port).close()
}
.retry(Schedule.linear(clockDuration) && Schedule.recurs(10))
}
override def spec: ZSpec[Environment, Failure] =
suite("MainTest")(
testM("Health check") {
for {
_ <- TestClock.adjust(clockDuration).fork
_ = println("1")
_ <- isLocalPortInUse(8080)
_ = println("2")
client <- Task(JavaNetClientBuilder[Task](blocker).create)
_ = println("3")
response <- client.expect[String]("http://localhost:8080/healthcheck")
_ = println("4")
} yield assert(response)(equalTo(""))
}
).provideCustomLayerShared(httpServer)
}
The problem is that as soon as the server starts, the test stops running and are not executed. The output is
1
checking for local port in use
checking for local port in use
<server init message>
In Suite "MainTest", test "Health check" has taken more than 1 m to execute. If this is not expected, consider using TestAspect.timeout to timeout runaway tests for faster diagnostics.
So as you can see, the tests run OK until the server starts and then does not continue the execution.
Also, how could I perform a POST call instead of a GET one? I'm a bit lost in the HTTP4S/ZIO ecosystem with http4sClients, ZHTTP, BlazeClientBuilders and the like. What would be the easiest way of doing a POST call to my server in a test like the previous one?
Cheers!
edit: I’ve checked that the server works fine while hanging in here, I can do CURL calls from a terminal and it responds correctly. So it seems clear that the problem is that as soon as the server is up it stays in the front, not background, and the tests do not have the chance to finish the execution.
You are advancing the clock by 1 second but your application might require more time to run. Also, your particular test will require infinite time to run because, while unit tests are instantaneous in ZIO, integration tests are not.
Advancing the time of a unit test by 1 second requires theoretically 0 seconds. This might not be enough for the port to become free.
Since you are trying to create an integration test, you should use a real Clock and not the one provided by the test kit.

Await for a Sequence of Futures with timeout without failing on TimeoutException

I have a sequence of scala Futures of same type.
I want, after some limited time, to get a result for the entire sequence while some futures may have succeeded, some may have failed and some haven't completed yet, the non completed futures should be considered failed.
I don't want to use Await each future sequentially.
I did look at this question: Scala waiting for sequence of futures
and try to use the solution from there, namely:
private def lift[T](futures: Seq[Future[T]])(implicit ex: ExecutionContext) =
futures.map(_.map { Success(_) }.recover { case t => Failure(t) })
def waitAll[T](futures: Seq[Future[T]])(implicit ex: ExecutionContext) =
Future.sequence(lift(futures))
futures: Seq[Future[MyObject]] = ...
val segments = Await.result(waitAll(futures), waitTimeoutMillis millis)
but I'm still getting a TimeoutException, I guess because some of the futures haven't completed yet.
and that answer also states,
Now Future.sequence(lifted) will be completed when every future is completed, and will represent successes and failures using Try.
But I want my Future to be completed after the timeout has passed, not when every future in the sequence has completed. What else can I do?
If I used raw Future (rather than some IO monad which has this functionality build-in, or without some Akka utils for exactly that) I would hack together utility like:
// make each separate future timeout
object FutureTimeout {
// separate EC for waiting
private val timeoutEC: ExecutorContext = ...
private def timeout[T](delay: Long): Future[T] = Future {
blocking {
Thread.sleep(delay)
}
throw new Exception("Timeout")
}(timeoutEC)
def apply[T](fut: Future[T], delat: Long)(
implicit ec: ExecutionContext
): Future[T] = Future.firstCompletedOf(Seq(
fut,
timeout(delay)
))
}
and then
Future.sequence(
futures
.map(FutureTimeout(_, delay))
.map(Success(_))
.recover { case e => Failure(e) }
)
Since each future would terminate at most after delay we would be able to collect them into one result right after that.
You have to remember though that no matter how would you trigger a timeout you would have no guarantee that the timeouted Future stops executing. It could run on and on on some thread somewhere, it's just that you wouldn't wait for the result. firstCompletedOf just makes this race more explicit.
Some other utilities (like e.g. Cats Effect IO) allow you to cancel computations (which is used in e.g. races like this one) but you still have to remember that JVM cannot arbitrarily "kill" a running thread, so that cancellation would happen after one stage of computation is completed and before the next one is started (so e.g. between .maps or .flatMaps).
If you aren't afraid of adding external deps there are other (and more reliable, as Thread.sleep is just a temporary ugly hack) ways of timing out a Future, like Akka utils. See also other questions like this.
Here is solution using monix
import monix.eval.Task
import monix.execution.Scheduler
val timeoutScheduler = Scheduler.singleThread("timeout") //it's safe to use single thread here because timeout tasks are very fast
def sequenceDiscardTimeouts[T](tasks: Task[T]*): Task[Seq[T]] = {
Task
.parSequence(
tasks
.map(t =>
t.map(Success.apply) // Map to success so we can collect the value
.timeout(500.millis)
.executeOn(timeoutScheduler) //This is needed to run timesouts in dedicated scheduler that won't be blocked by "blocking"/io work if you have any
.onErrorRecoverWith { ex =>
println("timed-out")
Task.pure(Failure(ex)) //It's assumed that any error is a timeout. It's possible to "catch" just timeout exception here
}
)
)
.map { res =>
res.collect { case Success(r) => r }
}
}
Testing code
implicit val mainScheduler = Scheduler.fixedPool(name = "main", poolSize = 10)
def slowTask(msg: String) = {
Task.sleep(Random.nextLong(1000).millis) //Sleep here to emulate a slow task
.map { _ =>
msg
}
}
val app = sequenceDiscardTimeouts(
slowTask("1"),
slowTask("2"),
slowTask("3"),
slowTask("4"),
slowTask("5"),
slowTask("6")
)
val started: Long = System.currentTimeMillis()
app.runSyncUnsafe().foreach(println)
println(s"Done in ${System.currentTimeMillis() - started} millis")
This will print an output different for each run but it should look like following
timed-out
timed-out
timed-out
3
4
5
Done in 564 millis
Please note the usage of two separate schedulers. This is to ensure that timeouts will fire even if the main scheduler is busy with business logic. You can test it by reducing poolSize for main scheduler.

Concurrency with scala.sys.process.ProcessBuilder

I'm using sPdf's run method to render HTML as a PDF file.
run uses scala.sys.process.ProcessBuilder and it's ! method:
/** Starts the process represented by this builder, blocks until it exits, and
* returns the exit code. Standard output and error are sent to the console.
*/
def ! : Int
My controller is using a Future to asynchronously execute the conversion but won't spdf block all other interim executions?
Future { pdf.run(sourceUrl, outputStream) } map { exitCode =>
outputSteam.toByteArray
}
UPDATE
Thanks for your answer Paul did a little test and yeah looks to be that way :)
If I update sPdf's run like so:
def run[A, B](sourceDocument: A, destinationDocument: B)(implicit sourceDocumentLike: SourceDocumentLike[A], destinationDocumentLike: DestinationDocumentLike[B]): Int = {
println("start/ " + System.currentTimeMillis)
< ... code removed ... >
val result = (sink compose source)(process).!
println("finish/ " + System.currentTimeMillis)
result
}
and I execute three consecutive requests the stdout prints
start 1461288779013
start 1461288779014
start 1461288779014
finish 1461288781018
finish 1461288781020
finish 1461288781020
Which looks like asynchronous execution.
This is Pdf#run:
def run[A, B](sourceDocument: A, destinationDocument: B)(implicit sourceDocumentLike: SourceDocumentLike[A], destinationDocumentLike: DestinationDocumentLike[B]): Int = {
val commandLine = toCommandLine(sourceDocument, destinationDocument)
val process = Process(commandLine)
def source = sourceDocumentLike.sourceFrom(sourceDocument) _
def sink = destinationDocumentLike.sinkTo(destinationDocument) _
(sink compose source)(process).!
}
There's no synchronization that prevents parallel execution. Assuming that the ExecutionContext has enough available threads,
Future { pdf.run(sourceUrl, outputStream) } map { exitCode =>
outputSteam.toByteArray
}
Future { pdf.run(sourceUrl, outputStream) } map { exitCode =>
outputSteam.toByteArray
}
will execute in parallel.
If instead, the run method had been, say, surrounded by a synchronized block, only one invocation would execute per Pdf instance. But there's no reason to prevent concurrency here, so the author didn't.

Simple Scala actor question

I'm sure this is a very simple question, but embarrassed to say I can't get my head around it:
I have a list of values in Scala.
I would like to use use actors to make some (external) calls with each value, in parallel.
I would like to wait until all values have been processed, and then proceed.
There's no shared values being modified.
Could anyone advise?
Thanks
There's an actor-using class in Scala that's made precisely for this kind of problem: Futures. This problem would be solved like this:
// This assigns futures that will execute in parallel
// In the example, the computation is performed by the "process" function
val tasks = list map (value => scala.actors.Futures.future { process(value) })
// The result of a future may be extracted with the apply() method, which
// will block if the result is not ready.
// Since we do want to block until all results are ready, we can call apply()
// directly instead of using a method such as Futures.awaitAll()
val results = tasks map (future => future.apply())
There you go. Just that.
Create workers and ask them for futures using !!; then read off the results (which will be calculated and come in in parallel as they're ready; you can then use them). For example:
object Example {
import scala.actors._
class Worker extends Actor {
def act() { Actor.loop { react {
case s: String => reply(s.length)
case _ => exit()
}}}
}
def main(args: Array[String]) {
val arguments = args.toList
val workers = arguments.map(_ => (new Worker).start)
val futures = for ((w,a) <- workers zip arguments) yield w !! a
val results = futures.map(f => f() match {
case i: Int => i
case _ => throw new Exception("Whoops--didn't expect to get that!")
})
println(results)
workers.foreach(_ ! None)
}
}
This does a very inexpensive computation--calculating the length of a string--but you can put something expensive there to make sure it really does happen in parallel (the last thing that case of the act block should be to reply with the answer). Note that we also include a case for the worker to shut itself down, and when we're all done, we tell the workers to shut down. (In this case, any non-string shuts down the worker.)
And we can try this out to make sure it works:
scala> Example.main(Array("This","is","a","test"))
List(4, 2, 1, 4)