5 lessons I learned as I continued to master ZIO

Hello. On the eve of the start of the "Scala developer" course, we have prepared a useful translation for you.


2020 (I, II) , ZIO. 9 . ZIO 1.0, ZIO ZLayer.

, ZIO — . , /, , .

ZIO . 5 , , ZIO. : ZIO assert- TestClock.

 Il Vagabiondo  Unsplash

1. ,

. (. ., , ) .

ZIO , JVM , . , .

Kafka.

(pollLoop) . , , . , - .

def pollLoop(running: Ref[Boolean],
             consumer: Consumer
            ): UIO[Unit] =
  running.get.flatMap {
    case true => for {
      _ <- pollAndHandle(consumer)
      result <- pollLoop(running, consumer)
    } yield result
    case false => ZIO.unit
  }

, for-, , . For- flatMap, map. , for- . ,  — map — .

def pollLoop(running: Ref[Boolean],
                 consumer: Consumer
                 ): UIO[Unit] =
  running.get.flatMap {
    case true => 
      pollAndHandle(consumer)
        .flatMap(_ => pollLoop(running, consumer))
        .map(result => result)
    case false => ZIO.unit
  }

 Greyhound ZIO doWhile, , . , (pollOnce), doWhile:

pollOnce(running, consumer).doWhile(_ == true).forkDaemon

, pollOnce UIO[boolean], , :

def pollOnce(running: Ref[Boolean],
                 consumer: Consumer
                 ): UIO[Unit] =
  running.get.flatMap {
    case true => for {
      _ <- pollAndHandle(consumer)
    } yield true
    case false => UIO(false)
  }

, - , .

2.

«» «» (. 2   2), , . :

def repeatedlyPublishQuote(stock: Stock) = {
  publishQuote(stock).repeat(Schedule.fixed(1.second))
}

def publishQuote(stock: Stock) = {
  println(s"getLatestQuote for $stock")
  for {
    quote <- grpcClient.getLatestQuote(stock)
    _ <- sendToWebsocket(quote)
  } yield ()
}

ZIO, publishQuote, repeat repeatedlyPublishQuote. repeat .

 — , ZIO. , - , .

, , , , console.putStrLn, for-, :

def publishQuote(stock: Stock) = {
  val sendQuote = for {
    _ <- console.putStrLn(s"getLatestQuote for $stock")
    quote <- grpcClient.getLatestQuote(stock)
    _ <- sendToWebsocket(quote)
  } yield ()
  
  sendQuote.catchAll(_ => UIO.unit)
}

, catchAll for-, . .

3. TestClock assert-

, « », , .  consumer, 1 , , .

- messageHandler , (assert), . , , .

.  specs2,  ScalaTest.

 TestClock,  ZIO, .  TestClock  , .

eventuallyZ:

def eventuallyZ[T](f: UIO[T])(predicate: T => Boolean): ZIO[Clock, Throwable, Unit] = {
  f.repeat(Schedule.spaced(100.milliseconds) && Schedule.doUntil(predicate))
    .timeoutFail(new RuntimeException)(4.seconds)
    .unit
}

Schedule ZIO 100 , - 4 .

. eventuallyZ Clock , , . Live Clock, , TestClock, eventuallyZ TestClock, , , TestClock.adjust .

 ZIO provideSomeLayer:

def eventuallyZ[T](f: UIO[T])(predicate: T => Boolean): ZIO[Clock, Throwable, Unit] = {
  f.repeat(Schedule.spaced(100.milliseconds) && Schedule.doUntil(predicate))
    .timeoutFail(new RuntimeException)(4.seconds)
    .provideSomeLayer(Clock.live)
    .unit
}

ZIO,  eventuallyZ,  Live Clock 100 . ,  TestClock.

.

4. assert- ZIO Test

: ZIO Test. : , :

object NumbersTest extends DefaultRunnableSpec {
  override def spec =
      testM("positive and even") {
        checkAll(Gen.fromIterable(Seq(0, 2, 4, 6))) { number =>
            assert(number)(isPositive)
            assert(number % 2 == 0)(Assertion.isTrue)
          }
      }
}

, , , , (, : Gen.anyInt.filter(_ > 0)). . isEven, assert . , , 0 .

+ positive and even after additionRan 1 test in 660 ms: 1 succeeded, 0 ignored, 0 failed

, assert-  &&:

assert(number)(isPositive) && assert(number % 2 == 0 (Assertion.isTrue)

:

Ran 1 test in 685 ms: 0 succeeded, 0 ignored, 1 failed
- positive and even after addition
Test failed after 1 iteration with input: 0
0 did not satisfy isGreaterThan(0)

5. , Managed#Acquire

(fibers) ZIO — , / , ZIO.

, foreachPar.

.  fork forkDaemon ( ). , ( ).

, ! ZManaged acquire release ( , ), , uninterruptible:

criticalEffect.uninterruptible

Managed.acquire , «heart-beat» .  Managed.release  ( ).

object Server extends zio.ManagedApp {
  def sendHeartBeat(): URIO[Console with Clock, Unit] =
    console.putStrLn("heart-beat").repeat(Schedule.fixed(1.second)).ignore

  override def run(args: List[String]): ZManaged[zio.ZEnv, Nothing, ExitCode] =
    Managed
      .make(sendHeartBeat().fork)(_.interrupt)
      .map(_ => ExitCode(0))
}

, fork , !

, ZIO, :

Managed.make(sendHeartBeat().fork.interruptible)(.interrupt)

:

sendHeartBeat().toManaged.fork

toManaged_ , Managed.make.

!

:

ZIO, Twitter Medium. - , .

.

:




All Articles