0

I have a topic subscriber in lagom as bellow

fooService.fooTopic().subscribe
  .atLeastOnce(
    Flow[fooMsg].map {
      case fooMsg(_) =>
        foo()
      case a =>
        println(a)
    }.async.map{ _ =>
      Done
    }
  )

to subscribe this topic, im using atLeastOnce as the method, so that if theres any exception, I want the flow to be restarted/retried. when im throwing a normal exception, it could keep retrying normally

  private def foo() = {
    throw new RuntimeException("testing error")
  }

but when the exception happens in the future, no matter how I tried it, the Flow wont restart. heres one of my tries to handle the exception in the future

  private def foo() = {
    val test: Future[Int] = Future(throw new RuntimeException("asd"))
    val result = for {
      y1 <- test
    } yield (y1)

    result.onComplete{
      case Success(value) => println("SUCCESS")
      case Failure(exception) => println(exception.getMessage)
                                 throw exception
    }
  }
  private def foo() = {
    val test: Future[Int] = Future(throw new RuntimeException("asd"))

    test.onComplete{
      case Success(value) => println("SUCCESS")
      case Failure(exception) => println(exception.getMessage)
                                 throw exception
    }
  }

it will show an exception, but the Flow wont restart it automatically. How should I handle/throw the exception in the Future?

Mark
  • 2,041
  • 2
  • 18
  • 35

1 Answers1

1

I think you do not need to restart full flow if you have failed only one future. I suggest retrying only Future. For instance, you can write code like this that will retry your call, replace Future.successful(10) on the call of your method:

        val test: Future[Int] = Future(throw new RuntimeException("asd")).recoverWith {
          case NonFatal(e) =>
            Future.successful(10)
        }

        val result = for {
          y1 <- test
        } yield (y1)

Also, you can write code as you want, it will fail and retry, but you need to return result of your Future:

  kafka.topic1.subscribe.atLeastOnce(Flow[String]
    .mapAsync(1) {
      case envelope: String =>

        val test: Future[String] = Future(throw new RuntimeException("asd"))
      /*.recoverWith {
          case NonFatal(e) =>
            Future.successful("10")
        }*/

        val result = for {
          y1 <- test
        } yield (y1)

        println(s"code block $envelope")
       result.onComplete{
          case Success(value) => println(s"Message from topic: $envelope $result")
          case Failure(exception) => println(exception.getMessage)
            throw exception
        }
      result.map(_ => Done)
    }
)
Vladislav Kievski
  • 1,637
  • 11
  • 12
  • in my case, I need to retry the whole flow if theres any exception. actually, the future result was received through http call. so that I need to retry my whole flow, and re-send the http call. my result was given by `async.map` – Mark Jul 09 '20 at 09:09
  • You can try second option, it will continuously retry until success – Vladislav Kievski Jul 09 '20 at 10:02
  • 2
    `map().async` (and `async.map()` for that matter) and `mapAsync()` are very different things. The `async` operator in a stream just means that there's an async boundary in the stream when materialized, so messages can be processed simultaneously on either side (pipelining). `mapAsync` (and the other operators which are some synchronous operator with `Async` appended) denotes that the logic of the stage is asynchronous (involving a future). – Levi Ramsey Jul 09 '20 at 14:37