cats.effect.concurrent.Deferred Scala Examples

The following examples show how to use cats.effect.concurrent.Deferred. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example.
Example 1
Source File: RebalanceEvents.scala    From aecor   with MIT License 5 votes vote down vote up
package aecor.kafkadistributedprocessing.internal

import java.util

import aecor.data.Committable
import cats.effect.concurrent.Deferred
import cats.effect.implicits._
import cats.effect.{ ConcurrentEffect, Effect }
import cats.implicits._
import fs2.Stream
import fs2.concurrent.Queue
import org.apache.kafka.clients.consumer.ConsumerRebalanceListener
import org.apache.kafka.common
import org.apache.kafka.common.TopicPartition

import scala.collection.JavaConverters._

private[kafkadistributedprocessing] object RebalanceEvents {
  final class UsePartiallyApplied[F[_]] {
    def subscribe[A](
      f: ConsumerRebalanceListener => F[Unit]
    )(implicit F: ConcurrentEffect[F]): F[Stream[F, Committable[F, RebalanceEvent]]] =
      for {
        queue <- Queue.unbounded[F, Committable[F, RebalanceEvent]]
        listener = new Listener[F](
          event =>
            Deferred[F, Unit]
              .flatMap { completion =>
                queue.enqueue1(Committable(completion.complete(()), event)) >> completion.get
            }
        )
        _ <- f(listener)
      } yield queue.dequeue
  }

  def apply[F[_]]: UsePartiallyApplied[F] = new UsePartiallyApplied[F]

  sealed abstract class RebalanceEvent
  object RebalanceEvent {
    final case class PartitionsRevoked(partitions: Set[TopicPartition]) extends RebalanceEvent
    final case class PartitionsAssigned(partitions: Set[TopicPartition]) extends RebalanceEvent
  }

  private final class Listener[F[_]: Effect](processEvent: RebalanceEvent => F[Unit])
      extends ConsumerRebalanceListener {

    override def onPartitionsRevoked(partitions: util.Collection[common.TopicPartition]): Unit =
      processEvent(RebalanceEvent.PartitionsRevoked(partitions.asScala.toSet)).toIO
        .unsafeRunSync()

    override def onPartitionsAssigned(partitions: util.Collection[common.TopicPartition]): Unit =
      processEvent(RebalanceEvent.PartitionsAssigned(partitions.asScala.toSet)).toIO
        .unsafeRunSync()
  }
} 
Example 2
Source File: ListProjector.scala    From event-sourcing-kafka-streams   with MIT License 5 votes vote down vote up
package org.amitayh.invoices.projector

import java.util.UUID

import cats.effect.concurrent.Deferred
import cats.effect.{ContextShift, IO}
import cats.syntax.apply._
import org.amitayh.invoices.common.Config
import org.amitayh.invoices.common.domain.InvoiceSnapshot
import org.amitayh.invoices.common.serde.AvroSerde.SnapshotSerde
import org.amitayh.invoices.common.serde.UuidSerde
import org.amitayh.invoices.dao.{InvoiceList, InvoiceRecord, MySqlInvoiceList}
import org.amitayh.invoices.streamprocessor.StreamProcessorApp
import org.apache.kafka.streams.kstream.{Consumed, ForeachAction, KeyValueMapper}
import org.apache.kafka.streams.{KeyValue, StreamsBuilder, Topology}

import scala.concurrent.ExecutionContext.global

object ListProjector extends StreamProcessorApp {

  override def appId: String = "invoices.processor.list-projector"

  override def topology: Topology = ListProjectorTopology.create.unsafeRunSync()

}

object ListProjectorTopology {
  implicit val contextShift: ContextShift[IO] = IO.contextShift(global)

  def create: IO[Topology] = for {
    deferred <- Deferred[IO, Topology]
    _ <- MySqlInvoiceList.resource[IO].use { invoiceList =>
      buildTopology(invoiceList).flatMap(deferred.complete) *> IO.never
    }.start
    topology <- deferred.get
  } yield topology

  private def buildTopology(invoiceList: InvoiceList[IO]): IO[Topology] = IO {
    val builder = new StreamsBuilder

    val snapshots = builder.stream(
      Config.Topics.Snapshots.name,
      Consumed.`with`(UuidSerde, SnapshotSerde))

    snapshots
      .map[UUID, InvoiceRecord](ToRecord)
      .foreach(new SaveInvoiceRecord(invoiceList))

    builder.build()
  }
}

object ToRecord extends KeyValueMapper[UUID, InvoiceSnapshot, KeyValue[UUID, InvoiceRecord]] {
  override def apply(id: UUID, snapshot: InvoiceSnapshot): KeyValue[UUID, InvoiceRecord] =
    KeyValue.pair(id, InvoiceRecord(id, snapshot))
}

class SaveInvoiceRecord(invoicesList: InvoiceList[IO])
  extends ForeachAction[UUID, InvoiceRecord] {

  override def apply(id: UUID, value: InvoiceRecord): Unit =
    invoicesList.save(value).unsafeRunSync()

} 
Example 3
Source File: resourcesuite.scala    From pfps-shopping-cart   with Apache License 2.0 5 votes vote down vote up
package suite

import cats.effect._
import cats.effect.concurrent.Deferred
import org.scalatest.BeforeAndAfterAll

trait ResourceSuite[A] extends PureTestSuite with BeforeAndAfterAll {

  def resources: Resource[IO, A]

  private[this] var res: A            = _
  private[this] var cleanUp: IO[Unit] = _

  private[this] val latch = Deferred[IO, Unit].unsafeRunSync()

  override def beforeAll(): Unit = {
    super.beforeAll()
    val (r, h) = resources.allocated.unsafeRunSync()
    res = r
    cleanUp = h
    latch.complete(()).unsafeRunSync()
  }

  override def afterAll(): Unit = {
    cleanUp.unsafeRunSync()
    super.afterAll()
  }

  def withResources(f: (=> A) => Unit): Unit = f {
    //to ensure that the resource has been allocated even before any spec(...) bodies
    latch.get.unsafeRunSync
    res
  }
} 
Example 4
Source File: PromiseMapper.scala    From laserdisc   with MIT License 5 votes vote down vote up
package laserdisc
package fs2

import cats.effect.concurrent.Deferred
import cats.effect.syntax.concurrent._
import cats.effect.{Concurrent, Timer}
import cats.syntax.flatMap._
import cats.syntax.monadError._
import shapeless.Poly1

import scala.concurrent.TimeoutException

object PromiseMapper extends Poly1 {
  private[this] final def mapper[F[_]: Concurrent: Timer, A](protocol: Protocol.Aux[A]): Env[F] => F[Maybe[A]] = {
    case (queue, duration) =>
      Deferred[F, Maybe[A]] >>= { promise =>
        queue.enqueue1(Request(protocol, promise.complete)) >> {
          promise.get
            .timeout(duration)
            .adaptError {
              case _: TimeoutException => RequestTimedOut(protocol)
            }
        }
      }
  }

  implicit def mkOne[F[_]: Timer: Concurrent, A]: Case.Aux[Protocol.Aux[A], Env[F] => F[Maybe[A]]] = at[Protocol.Aux[A]](mapper(_))
} 
Example 5
Source File: NettySocket.scala    From asyncdb   with Apache License 2.0 5 votes vote down vote up
package io.asyncdb
package netty

import cats.syntax.all._
import cats.effect._
import cats.effect.concurrent.Deferred
import io.netty.bootstrap.Bootstrap
import io.netty.channel.Channel

trait NettySocketConfig {
  val bootstrap: Bootstrap
}

abstract class NettySocket[F[_], M](
  config: NettySocketConfig,
  channelHolder: Deferred[F, Either[Throwable, Channel]]
)(
  implicit F: Concurrent[F]
) extends Socket[F, M] {

  protected def open = F.delay(config.bootstrap.connect()).flatMap { f =>
    f.to[F]
      .attempt
      .flatMap { e =>
        channelHolder.complete(e.map(_.channel()))
      }
      .as(this)
  }

  protected def close = channel.flatMap(ch => F.delay(ch.close()))

  protected def channel = channelHolder.get.rethrow

} 
Example 6
Source File: ConcurrentEffectLaws.scala    From cats-effect   with Apache License 2.0 5 votes vote down vote up
package cats
package effect
package laws

import cats.effect.concurrent.Deferred
import cats.implicits._
import cats.laws._

import scala.concurrent.Promise

trait ConcurrentEffectLaws[F[_]] extends ConcurrentLaws[F] with EffectLaws[F] {
  implicit def F: ConcurrentEffect[F]

  def runAsyncRunCancelableCoherence[A](fa: F[A]) = {
    val fa1 = IO.async[A] { cb =>
      F.runAsync(fa)(r => IO(cb(r))).unsafeRunSync()
    }
    val fa2 = IO.cancelable[A] { cb =>
      F.toIO(F.runCancelable(fa)(r => IO(cb(r))).unsafeRunSync())
    }
    fa1 <-> fa2
  }

  def runCancelableIsSynchronous[A] = {
    val lh = Deferred.uncancelable[F, Unit].flatMap { latch =>
      val spawned = Promise[Unit]()
      // Never ending task
      val ff = F.cancelable[A] { _ =>
        spawned.success(()); latch.complete(())
      }
      // Execute, then cancel
      val token = F.delay(F.runCancelable(ff)(_ => IO.unit).unsafeRunSync()).flatMap { cancel =>
        // Waiting for the task to start before cancelling it
        Async.fromFuture(F.pure(spawned.future)) >> cancel
      }
      F.liftIO(F.runAsync(token)(_ => IO.unit).toIO) *> latch.get
    }
    lh <-> F.unit
  }

  def runCancelableStartCancelCoherence[A](a: A) = {
    // Cancellation via runCancelable
    val f1: F[A] = for {
      effect1 <- Deferred.uncancelable[F, A]
      latch <- F.delay(Promise[Unit]())
      never = F.cancelable[A] { _ =>
        latch.success(()); effect1.complete(a)
      }
      cancel <- F.liftIO(F.runCancelable(never)(_ => IO.unit).toIO)
      // Waiting for the task to start before cancelling it
      _ <- Async.fromFuture(F.pure(latch.future)) // TODO get rid of this, IO, and Future here
      _ <- cancel
      result <- effect1.get
    } yield result

    // Cancellation via start.flatMap(_.cancel)
    val f2: F[A] = for {
      effect2 <- Deferred.uncancelable[F, A]
      // Using a latch to ensure that the task started
      latch <- Deferred.uncancelable[F, Unit]
      never = F.bracket(latch.complete(()))(_ => F.never[Unit])(_ => effect2.complete(a))
      fiber <- F.start(never)
      // Waiting for the task to start before cancelling it
      _ <- latch.get
      _ <- F.start(fiber.cancel)
      result <- effect2.get
    } yield result

    f1 <-> f2
  }

  def toIORunCancelableConsistency[A](fa: F[A]) =
    ConcurrentEffect.toIOFromRunCancelable(fa) <-> F.toIO(fa)
}

object ConcurrentEffectLaws {
  def apply[F[_]](implicit F0: ConcurrentEffect[F], contextShift0: ContextShift[F]): ConcurrentEffectLaws[F] =
    new ConcurrentEffectLaws[F] {
      val F = F0
      val contextShift = contextShift0
    }
} 
Example 7
Source File: AsyncLaws.scala    From cats-effect   with Apache License 2.0 5 votes vote down vote up
package cats
package effect
package laws

import cats.effect.ExitCase.{Completed, Error}
import cats.effect.concurrent.Deferred
import cats.implicits._
import cats.laws._

import scala.util.Either

trait AsyncLaws[F[_]] extends SyncLaws[F] {
  implicit def F: Async[F]

  def asyncRightIsPure[A](a: A) =
    F.async[A](_(Right(a))) <-> F.pure(a)

  def asyncLeftIsRaiseError[A](e: Throwable) =
    F.async[A](_(Left(e))) <-> F.raiseError(e)

  def repeatedAsyncEvaluationNotMemoized[A](a: A, f: A => A) =
    F.suspend {
      var cur = a

      val change: F[Unit] = F.async { cb =>
        cur = f(cur)
        cb(Right(()))
      }

      val read: F[A] = F.delay(cur)

      change *> change *> read
    } <-> F.pure(f(f(a)))

  def repeatedAsyncFEvaluationNotMemoized[A](a: A, f: A => A) =
    F.suspend {
      var cur = a

      val change: F[Unit] = F.asyncF { cb =>
        cur = f(cur)
        F.delay(cb(Right(())))
      }

      val read: F[A] = F.delay(cur)

      change *> change *> read
    } <-> F.pure(f(f(a)))

  def repeatedCallbackIgnored[A](a: A, f: A => A) =
    F.suspend {
      var cur = a
      val change = F.delay { cur = f(cur) }
      val readResult = F.delay(cur)

      val double: F[Unit] = F.async { cb =>
        cb(Right(()))
        cb(Right(()))
      }

      double *> change *> readResult
    } <-> F.delay(f(a))

  def propagateErrorsThroughBindAsync[A](t: Throwable) = {
    val fa = F.attempt(F.async[A](_(Left(t))).flatMap(x => F.pure(x)))
    fa <-> F.pure(Left(t))
  }

  def neverIsDerivedFromAsync[A] =
    F.never[A] <-> F.async[A](_ => ())

  def asyncCanBeDerivedFromAsyncF[A](k: (Either[Throwable, A] => Unit) => Unit) =
    F.async(k) <-> F.asyncF(cb => F.delay(k(cb)))

  def bracketReleaseIsCalledOnCompletedOrError[A, B](fa: F[A], b: B) = {
    val lh = Deferred.uncancelable[F, B].flatMap { promise =>
      val br = F.bracketCase(F.delay(promise)) { _ =>
        fa
      } {
        case (r, Completed | Error(_)) => r.complete(b)
        case _                         => F.unit
      }
      // Start and forget
      // we attempt br because even if fa fails, we expect the release function
      // to run and set the promise.
      F.asyncF[Unit](cb => F.delay(cb(Right(()))) *> br.attempt.as(())) *> promise.get
    }
    lh <-> F.pure(b)
  }
}

object AsyncLaws {
  def apply[F[_]](implicit F0: Async[F]): AsyncLaws[F] = new AsyncLaws[F] {
    val F = F0
  }
} 
Example 8
Source File: SqsSpec.scala    From fs2-aws   with MIT License 5 votes vote down vote up
package fs2.aws

import cats.effect.concurrent.Deferred
import cats.effect.{ ContextShift, IO }
import com.amazon.sqs.javamessaging.SQSConnection
import com.amazon.sqs.javamessaging.message.SQSTextMessage
import eu.timepit.refined.auto._
import fs2.aws
import fs2.aws.sqs.{ ConsumerBuilder, SQSConsumer, SqsConfig }
import javax.jms.{ Message, MessageListener, TextMessage }
import org.mockito.scalatest.MockitoSugar
import org.scalatest.flatspec.AsyncFlatSpec
import org.scalatest.matchers.should.Matchers

import scala.concurrent.ExecutionContext

class SqsSpec extends AsyncFlatSpec with Matchers with MockitoSugar {
  implicit val ec: ExecutionContext             = ExecutionContext.global
  implicit val ioContextShift: ContextShift[IO] = IO.contextShift(ec)
  implicit val messageDecoder: Message => Either[Throwable, Int] = { sqs_msg =>
    val text = sqs_msg.asInstanceOf[TextMessage].getText
    if ("fail" == text) Left(intercept[Exception](()))
    else Right(text.toInt)
  }
  "SQS endpoint" should "stream messages" in {

    def stream(d: Deferred[IO, MessageListener]) =
      aws
        .sqsStream[IO, Int](
          SqsConfig("dummy"),
          (_, listener) =>
            new ConsumerBuilder[IO] {
              override def start: IO[SQSConsumer] =
                IO.delay(new SQSConsumer {
                  override def callback: MessageListener = listener

                  override def startConsumer(): Unit = ()

                  override def shutdown(): Unit = ()

                  override def connection: SQSConnection = mock[SQSConnection]
                })
            },
          Some(d)
        )
        .take(4)
        .compile
        .toList

    val r = for {
      d <- Deferred[IO, MessageListener]
      res <- IO.racePair(stream(d), d.get).flatMap {
              case Right((streamFiber, listener)) =>
                listener.onMessage(new SQSTextMessage("1"))
                listener.onMessage(new SQSTextMessage("2"))
                listener.onMessage(new SQSTextMessage("fail"))
                listener.onMessage(new SQSTextMessage("4"))
                listener.onMessage(new SQSTextMessage("5"))
                streamFiber.join
              case _ => IO(Nil)
            }
    } yield res

    val future = r.unsafeToFuture()

    future.map(_ should be(List(1, 2, 4, 5)))
  }
} 
Example 9
Source File: package.scala    From fs2-aws   with MIT License 5 votes vote down vote up
package fs2

import cats.effect.concurrent.Deferred
import cats.effect.{ ConcurrentEffect, IO }
import fs2.aws.sqs.{ ConsumerBuilder, ReceiverCallback, SqsConfig }
import fs2.concurrent.Queue
import javax.jms.{ Message, MessageListener }

package object aws {

  def sqsStream[F[_], O](
    sqsConfig: SqsConfig,
    builder: (SqsConfig, MessageListener) => ConsumerBuilder[F],
    d: Option[Deferred[F, MessageListener]] = None
  )(implicit F: ConcurrentEffect[F], decoder: Message => Either[Throwable, O]): fs2.Stream[F, O] =
    for {
      q        <- fs2.Stream.eval(Queue.unbounded[F, Either[Throwable, O]])
      callback <- fs2.Stream.eval(callback(q))
      _        <- fs2.Stream.eval(d.map(_.complete(callback)).getOrElse(F.unit))
      item     <- builder(sqsConfig, callback).serve(q.dequeue.rethrow)
    } yield item

  def callback[F[_], O](queue: Queue[F, Either[Throwable, O]])(
    implicit F: ConcurrentEffect[F],
    decoder: Message => Either[Throwable, O]
  ): F[ReceiverCallback[Either[Throwable, O]]] =
    F.delay(
      new ReceiverCallback[Either[Throwable, O]](r =>
        F.runAsync(queue.enqueue1(r))(_ => IO.unit).unsafeRunSync()
      )
    )

} 
Example 10
Source File: package.scala    From fs2-aws   with MIT License 5 votes vote down vote up
package fs2.aws

import cats.effect.ConcurrentEffect
import cats.effect.concurrent.Deferred
import eu.timepit.refined.auto._
import fs2.aws.sqs.SqsConfig
import javax.jms.{ Message, MessageListener }
import scala.concurrent.duration._

package object testkit {
  def sqsStream[F[_]: ConcurrentEffect, O](
    d: Deferred[F, MessageListener]
  )(implicit decoder: Message => Either[Throwable, O]): fs2.Stream[F, O] =
    fs2.aws.sqsStream(
      SqsConfig("dummy"),
      (_: SqsConfig, _: MessageListener) => new TestSqsConsumerBuilder[F],
      Some(d)
    )

  val TestRecordProcessor = new kinesis.SingleRecordProcessor(_ => (), 10.seconds)
} 
Example 11
Source File: lift.scala    From tofu   with Apache License 2.0 5 votes vote down vote up
package tofu.syntax

import cats.{Functor, ~>}
import cats.effect.concurrent.{Deferred, MVar, Ref, Semaphore}
import tofu.lift.{IsoK, Lift, Unlift}
import cats.tagless.{FunctorK, InvariantK}
import tofu.lift.{IsoK, Lift, Unlift}

object lift {
  implicit final class LiftSyntax[F[_], A](private val fa: F[A]) extends AnyVal {
    def lift[G[_]](implicit lift: Lift[F, G]): G[A] = lift.lift(fa)
  }

  implicit final class MVarLiftSyntax[F[_], A](private val mvar: MVar[F, A]) extends AnyVal {
    def lift[G[_]](implicit lift: Lift[F, G]): MVar[G, A] = mvar.mapK(lift.liftF)
  }

  implicit final class RefLiftSyntax[F[_], A](private val ref: Ref[F, A]) extends AnyVal {
    def lift[G[_]](implicit lift: Lift[F, G], F: Functor[F]): Ref[G, A] = ref.mapK(lift.liftF)
  }

  implicit final class DeferredLiftSyntax[F[_], A](private val deferred: Deferred[F, A]) extends AnyVal {
    def lift[G[_]](implicit lift: Lift[F, G]): Deferred[G, A] = deferred.mapK(lift.liftF)
  }

  implicit final class SemaphoreLiftSyntax[F[_]](private val semaphore: Semaphore[F]) extends AnyVal {
    def ilift[G[_]](implicit lift: IsoK[F, G]): Semaphore[G]                        = semaphore.imapK(lift.tof, lift.fromF)
    def unlift[G[_]](implicit unlift: Unlift[F, G], G: Functor[G]): G[Semaphore[G]] =
      G.map(unlift.unlift)(backf => semaphore.imapK(unlift.liftF, backf))
  }

  implicit final class CatsTaglessLiftSyntax[T[_[_]], F[_]](private val tf: T[F]) extends AnyVal {
    def lift[G[_]](implicit lift: Lift[F, G], fk: FunctorK[T]): T[G]                           = fk.mapK(tf)(lift.liftF)
    def ilift[G[_]](implicit lift: IsoK[F, G], fk: InvariantK[T]): T[G]                        = fk.imapK(tf)(lift.tof)(lift.fromF)
    def unlift[G[_]](implicit unlift: Unlift[F, G], G: Functor[G], fk: InvariantK[T]): G[T[G]] =
      G.map(unlift.unlift)(backf => fk.imapK(tf)(unlift.liftF)(backf))
  }

  implicit final class CatsTagless1LiftSyntax[T[_[_], _], F[_], A](private val tf: T[F, A]) extends AnyVal {
    def mapK1[G[_]](f: F ~> G)(implicit fk: FunctorK[T[*[_], A]]): T[G, A]               = fk.mapK(tf)(f)
    def imapK1[G[_]](f: F ~> G)(g: G ~> F)(implicit fk: InvariantK[T[*[_], A]]): T[G, A] = fk.imapK(tf)(f)(g)

    def lift1[G[_]](implicit lift: Lift[F, G], fk: FunctorK[T[*[_], A]]): T[G, A]                           = fk.mapK(tf)(lift.liftF)
    def ilift1[G[_]](implicit lift: IsoK[F, G], fk: InvariantK[T[*[_], A]]): T[G, A]                        =
      fk.imapK(tf)(lift.tof)(lift.fromF)
    def unlift1[G[_]](implicit unlift: Unlift[F, G], G: Functor[G], fk: InvariantK[T[*[_], A]]): G[T[G, A]] =
      G.map(unlift.unlift)(backf => fk.imapK(tf)(unlift.liftF)(backf))
  }

  implicit final class CatsTagless2LiftSyntax[T[_[_], _, _], F[_], A, B](private val tf: T[F, A, B]) extends AnyVal {
    def mapK2[G[_]](f: F ~> G)(implicit fk: FunctorK[T[*[_], A, B]]): T[G, A, B]               = fk.mapK(tf)(f)
    def imapK2[G[_]](f: F ~> G)(g: G ~> F)(implicit fk: InvariantK[T[*[_], A, B]]): T[G, A, B] = fk.imapK(tf)(f)(g)

    def lift2[G[_]](implicit lift: Lift[F, G], fk: FunctorK[T[*[_], A, B]]): T[G, A, B]                           = fk.mapK(tf)(lift.liftF)
    def ilift2[G[_]](implicit lift: IsoK[F, G], fk: InvariantK[T[*[_], A, B]]): T[G, A, B]                        =
      fk.imapK(tf)(lift.tof)(lift.fromF)
    def unlift2[G[_]](implicit unlift: Unlift[F, G], G: Functor[G], fk: InvariantK[T[*[_], A, B]]): G[T[G, A, B]] =
      G.map(unlift.unlift)(backf => fk.imapK(tf)(unlift.liftF)(backf))
  }
} 
Example 12
Source File: MakeDeferred.scala    From tofu   with Apache License 2.0 5 votes vote down vote up
package tofu.concurrent

import cats.effect.concurrent.{Deferred, TryableDeferred}
import cats.effect.{Concurrent, Sync}

trait MakeDeferred[I[_], F[_]] {
  def deferred[A]: I[Deferred[F, A]]
}

trait TryableDeferreds[F[_]] extends MakeDeferred[F, F] {
  def tryable[A]: F[TryableDeferred[F, A]]
}

object Deferreds {
  def apply[F[_], A](implicit make: Deferreds[F]): F[Deferred[F, A]] = make.deferred[A]
}

object MakeDeferred extends PolymorphicMakeDefferedInstance {
  def apply[I[_], F[_], A](implicit make: MakeDeferred[I, F]): I[Deferred[F, A]] = make.deferred[A]

  def tryable[F[_], A](implicit make: TryableDeferreds[F]): F[TryableDeferred[F, A]] = make.tryable[A]

  implicit def concurrentTryableDeferreds[F[_]: Concurrent]: TryableDeferreds[F] = new TryableDeferreds[F] {
    def deferred[A]: F[Deferred[F, A]]       = Deferred[F, A]
    def tryable[A]: F[TryableDeferred[F, A]] = Deferred.tryable[F, A]
  }
}
trait PolymorphicMakeDefferedInstance {
  implicit def concurrentMakeDeferred[I[_]: Sync, F[_]: Concurrent]: MakeDeferred[I, F] = new MakeDeferred[I, F] {
    def deferred[A]: I[Deferred[F, A]] = Deferred.in[I, F, A]
  }
} 
Example 13
Source File: Memoize.scala    From tofu   with Apache License 2.0 5 votes vote down vote up
package tofu.memo

import cats.effect.{Concurrent, ExitCase}
import cats.effect.concurrent.{Deferred, Ref}
import simulacrum.typeclass
import tofu.syntax.monadic._
import cats.syntax.option._
import cats.effect.syntax.concurrent._
import cats.effect.syntax.bracket._


  def memoizeOnSuccess[A](fa: F[A]): F[F[A]]
}

object Memoize {
  def concurrentMemoize[F[_]](implicit F: Concurrent[F]): Memoize[F] =
    new Memoize[F] {
      def memoize[A](fa: F[A]): F[F[A]] = Concurrent.memoize(fa)

      //copy of Concurrent.memoize accepting success only
      def memoizeOnSuccess[A](f: F[A]): F[F[A]] = {
        {
          sealed trait State
          case class Subs(n: Int) extends State
          case object Done        extends State

          case class Fetch(state: State, v: Deferred[F, A], stop: Deferred[F, F[Unit]])

          Ref[F].of(Option.empty[Fetch]).map { state =>
            (Deferred[F, A] product Deferred[F, F[Unit]]).flatMap {
              case (v, stop) =>
                def endState(ec: ExitCase[Throwable]) =
                  state.modify {
                    case None                          => throw new AssertionError("unreachable")
                    case s @ Some(Fetch(Done, _, _))   => s -> F.unit
                    case Some(Fetch(Subs(n), v, stop)) =>
                      if (ec == ExitCase.Canceled && n == 1) None -> stop.get.flatten
                      else if (ec == ExitCase.Canceled) Fetch(Subs(n - 1), v, stop).some -> F.unit
                      else Fetch(Done, v, stop).some                                     -> F.unit
                  }.flatten

                def fetch =
                  f.flatMap(v.complete)
                    .start
                    .flatMap(fiber => stop.complete(fiber.cancel))

                state.modify {
                  case s @ Some(Fetch(Done, v, _))   =>
                    s -> v.get
                  case Some(Fetch(Subs(n), v, stop)) =>
                    Fetch(Subs(n + 1), v, stop).some -> v.get.guaranteeCase(endState)
                  case None                          =>
                    Fetch(Subs(1), v, stop).some -> fetch.bracketCase(_ => v.get) { case (_, ec) => endState(ec) }
                }.flatten
            }
          }
        }
      }
    }
} 
Example 14
Source File: ZioTofuConcurrentInstance.scala    From tofu   with Apache License 2.0 5 votes vote down vote up
package tofu.zioInstances
import cats.effect.concurrent.Deferred
import tofu.concurrent._
import tofu.zioInstances.ZIODaemon.exitMap
import zio.{Exit => _, _}

abstract class ZioTofuConcurrentInstance[R1, E1, R, E]
    extends MakeConcurrent[ZIO[R1, E1, *], ZIO[R, E, *]] with Daemonic[ZIO[R, E, *], Cause[E]]

class ZioTofuConcurrentInstanceUIO[R, E] extends ZioTofuConcurrentInstance[Any, Nothing, R, E] {
  def deferred[A]: UIO[Deferred[ZIO[R, E, *], A]] =
    Promise.make[E, A].map(ZioDeferred(_))

  def qvarOf[A](a: A): ZIO[Any, Nothing, QVar[ZIO[R, E, *], A]] =
    Queue.bounded[A](1).tap(_.offer(a)).map(ZioQVar(_))

  def qvarEmpty[A]: ZIO[Any, Nothing, QVar[ZIO[R, E, *], A]] =
    Queue.bounded[A](1).map(ZioQVar(_))

  def gatekeeper(available: Long): ZIO[Any, Nothing, Gatekeeper[ZIO[R, E, *], Long]] =
    Semaphore.make(available).map(ZioGatekeeper(_, available))

  def atom[A](a: A): ZIO[Any, Nothing, Atom[ZIO[R, E, *], A]] = Ref.make(a).map(ZioAtom(_))

  def agentOf[A](a: A): ZIO[Any, Nothing, Agent[ZIO[R, E, *], A]] = RefM.make(a).map(ZioAgent(_))

  def daemonize[A](process: ZIO[R, E, A]): ZIO[R, E, Daemon[ZIO[R, E, *], Cause[E], A]] =
    process.forkDaemon.map(ZIODaemon(_))
}

final case class ZioDeferred[R, E, A](p: zio.Promise[E, A]) extends Deferred[ZIO[R, E, *], A] {
  def get: ZIO[R, E, A]               = p.await
  def complete(a: A): ZIO[R, E, Unit] = p.succeed(a).unit
}

final case class ZioAtom[R, E, A](r: zio.Ref[A]) extends Atom[ZIO[R, E, *], A] {
  def get: ZIO[R, E, A]                       = r.get
  def set(a: A): ZIO[R, E, Unit]              = r.set(a)
  def getAndSet(a: A): ZIO[R, E, A]           = r.modify(a1 => (a1, a))
  def update(f: A => A): ZIO[R, E, Unit]      = r.update(f).unit
  def modify[B](f: A => (A, B)): ZIO[R, E, B] = r.modify(f(_).swap)
}

final case class ZioQVar[R, E, A](r: zio.Queue[A]) extends QVar[ZIO[R, E, *], A] {
  def isEmpty: ZIO[R, E, Boolean] = r.size.map(_ == 0)
  def put(a: A): ZIO[R, E, Unit]  = r.offer(a).unit
  def take: ZIO[R, E, A]          = r.take
  def read: ZIO[R, E, A]          = r.poll.some.orElse(r.take.tap(r.offer).uninterruptible)
}

final case class ZioGatekeeper[R, E](r: zio.Semaphore, size: Long) extends Gatekeeper[ZIO[R, E, *], Long] {
  def available: ZIO[R, E, Long]                                = r.available
  def taken: ZIO[R, E, Long]                                    = r.available.map(size - _)
  def withPermit[B](t: ZIO[R, E, B]): ZIO[R, E, B]              = r.withPermit(t)
  def withPermitN[B](take: Long)(t: ZIO[R, E, B]): ZIO[R, E, B] = r.withPermits(take)(t)
}

final case class ZIODaemon[R, E, A](fib: zio.Fiber[E, A]) extends Daemon[ZIO[R, E, *], Cause[E], A] {
  def join: ZIO[R, E, A]                         = fib.join
  def cancel: ZIO[R, E, Unit]                    = fib.interrupt.unit
  def poll: ZIO[R, E, Option[Exit[Cause[E], A]]] = fib.poll.map(_.map(exitMap))
  def exit: ZIO[R, E, Exit[Cause[E], A]]         = fib.await.map(exitMap)
}

final case class ZioAgent[R, E, A](refm: RefM[A]) extends Agent[ZIO[R, E, *], A] {
  def get: ZIO[R, E, A]                                                                  = refm.get
  def updateM(f: A => ZIO[R, E, A]): ZIO[R, E, A]                                        = refm.getAndUpdate(f)
  def fireUpdateM(f: A => ZIO[R, E, A]): ZIO[R, E, Unit]                                 = refm.update(f).forkDaemon.unit
  def modifyM[B](f: A => ZIO[R, E, (B, A)]): ZIO[R, E, B]                                = refm.modify(f)
  def updateSomeM(f: PartialFunction[A, ZIO[R, E, A]]): ZIO[R, E, A]                     = refm.getAndUpdateSome(f)
  def modifySomeM[B](default: B)(f: PartialFunction[A, ZIO[R, E, (B, A)]]): ZIO[R, E, B] = refm.modifySome(default)(f)
}

object ZIODaemon {
  private[ZIODaemon] def exitMap[E, A](e: zio.Exit[E, A]): Exit[Cause[E], A] =
    e match {
      case zio.Exit.Success(a) => Exit.Completed(a)
      case zio.Exit.Failure(e) => if (e.interrupted) Exit.Canceled else Exit.Error(e)
    }
} 
Example 15
Source File: KafkaDistributedProcessingTest.scala    From aecor   with MIT License 5 votes vote down vote up
package aecor.kafkadistributedprocessing

import cats.effect.concurrent.{ Deferred, Ref }
import cats.effect.{ ExitCase, IO }
import cats.implicits._
import fs2.concurrent.Queue
import org.apache.kafka.clients.consumer.ConsumerConfig
import org.scalatest.funsuite.AnyFunSuiteLike
import scala.concurrent.duration._
class KafkaDistributedProcessingTest extends AnyFunSuiteLike with KafkaSupport with IOSupport {

  val topicName = "process-distribution"

  createCustomTopic(topicName, partitions = 4)

  val settings =
    DistributedProcessingSettings(Set(s"localhost:${kafkaConfig.kafkaPort}"), topicName)

  test("Process error propagation") {
    val exception = new RuntimeException("Oops!")

    val result = DistributedProcessing(settings)
      .start("Process error propagation", List(IO.raiseError[Unit](exception)))
      .attempt
      .timeout(20.seconds)
      .unsafeRunSync()

    assert(result == Left(exception))
  }

  test("Process lifecycle") {

    val test = Ref.of[IO, (Boolean, Boolean)]((false, false)).flatMap { ref =>
      Deferred[IO, Unit]
        .flatMap { done =>
          val process =
            ref.set((true, false)) >>
              done.complete(()) >>
              IO.never.guaranteeCase {
                case ExitCase.Canceled => ref.set((true, true))
                case _                 => IO.unit
              }.void

          val run = DistributedProcessing(settings)
            .start("Process lifecycle", List(process))

          IO.race(run, done.get) >> ref.get
        }
    }

    val (started, finished) = test.timeout(20.seconds).unsafeRunSync()

    assert(started)
    assert(finished)
  }

  test("Process distribution") {
    val test = Queue.unbounded[IO, Int].flatMap { queue =>
      def run(client: Int) =
        DistributedProcessing(
          settings.withConsumerSetting(ConsumerConfig.CLIENT_ID_CONFIG, client.toString)
        ).start(
          "Process distribution",
          Stream
            .from(0)
            .take(8)
            .map { n =>
              val idx = client * 10 + n
              (queue.enqueue1(idx) >> IO.cancelBoundary <* IO.never)
                .guarantee(queue.enqueue1(-idx))
            }
            .toList
        )

      def dequeue(size: Long): IO[List[Int]] =
        queue.dequeue.take(size).compile.to[List]

      for {
        d1 <- run(1).start
        s1 <- dequeue(8)
        d2 <- run(2).start
        s2 <- dequeue(16)
        _ <- d1.cancel
        s3 <- dequeue(16)
        _ <- d2.cancel
        s4 <- dequeue(8)
      } yield (s1, s2, s3, s4)
    }

    val (s1, s2, s3, s4) = test.timeout(20.seconds).unsafeRunSync()

    assert(s1.toSet == Set(10, 11, 12, 13, 14, 15, 16, 17))
    assert((s1 ++ s2 ++ s3 ++ s4).sum == 0)
  }

} 
Example 16
Source File: Channel.scala    From aecor   with MIT License 5 votes vote down vote up
package aecor.kafkadistributedprocessing.internal

import aecor.kafkadistributedprocessing.internal
import aecor.kafkadistributedprocessing.internal.Channel.CompletionCallback
import cats.effect.Concurrent
import cats.effect.concurrent.Deferred
import cats.effect.implicits._
import cats.implicits._

private[kafkadistributedprocessing] final case class Channel[F[_]](watch: F[CompletionCallback[F]],
                                                                   close: F[Unit],
                                                                   call: F[Unit])

private[kafkadistributedprocessing] object Channel {
  type CompletionCallback[F[_]] = F[Unit]
  def create[F[_]: Concurrent]: F[Channel[F]] =
    for {
      deferredCallback <- Deferred[F, CompletionCallback[F]]
      closed <- Deferred[F, Unit]
      close = closed.complete(())
      watch = deferredCallback.get
      call = Deferred[F, Unit]
        .flatMap { deferredCompletion =>
          deferredCallback
            .complete(deferredCompletion.complete(()).attempt.void) >> deferredCompletion.get
        }
        .race(closed.get)
        .void

    } yield internal.Channel(watch, close, call)
} 
Example 17
Source File: IncomingManager.scala    From iotchain   with MIT License 5 votes vote down vote up
package jbok.core.peer

import java.net.InetSocketAddress
import java.nio.channels.AsynchronousChannelGroup

import cats.effect._
import cats.effect.concurrent.Deferred
import cats.effect.implicits._
import cats.implicits._
import fs2._
import fs2.io.tcp.Socket
import javax.net.ssl.SSLContext
import jbok.common.log.Logger
import jbok.core.config.FullConfig
import jbok.core.ledger.History
import jbok.core.queue.Queue
import jbok.network.Message
import jbok.network.tcp.implicits._

final class IncomingManager[F[_]](config: FullConfig, history: History[F], ssl: Option[SSLContext], val inbound: Queue[F, Peer[F], Message[F]])(
    implicit F: ConcurrentEffect[F],
    cs: ContextShift[F],
    acg: AsynchronousChannelGroup
) extends BaseManager[F](config, history) {
  private val log = Logger[F]

  val localBindAddress: Deferred[F, InetSocketAddress] = Deferred.unsafe[F, InetSocketAddress]

  val localPeerUri: F[PeerUri] = localBindAddress.get.map(addr => PeerUri.fromTcpAddr(addr))

  val peers: Stream[F, Resource[F, (Peer[F], Socket[F])]] =
    Socket
      .serverWithLocalAddress[F](
        address = config.peer.bindAddr,
        maxQueued = 10,
        reuseAddress = true,
        receiveBufferSize = config.peer.bufferSize
      )
      .flatMap {
        case Left(bound) =>
          Stream.eval_(log.i(s"IncomingManager successfully bound to address ${bound}") >> localBindAddress.complete(bound))
        case Right(res) =>
          Stream.emit {
            for {
              socket    <- res
              tlsSocket <- Resource.liftF(socket.toTLSSocket(ssl, client = false))
              peer      <- Resource.liftF(handshake(socket))
              _         <- Resource.make(connected.update(_ + (peer.uri -> (peer -> socket))).as(peer))(peer => connected.update(_ - peer.uri))
              _         <- Resource.liftF(log.i(s"accepted incoming peer ${peer.uri}"))
            } yield (peer, tlsSocket)
          }
      }

  val serve: Stream[F, Unit] =
    peers
      .map { res =>
        Stream
          .resource(res)
          .flatMap {
            case (peer, socket) =>
              Stream(
                socket
                  .reads(config.peer.bufferSize, None)
                  .through(Message.decodePipe[F])
                  .map(m => peer -> m)
                  .through(inbound.sink)
                  .onFinalize(log.i(s"disconnected incoming ${peer.uri}") >> connected.update(_ - peer.uri)),
                peer.queue.dequeue.through(Message.encodePipe[F]).through(socket.writes(None))
              ).parJoinUnbounded
          }
          .handleErrorWith(e => Stream.eval(log.w(s"handle incoming peer failure: ${e}", e)))
      }
      .parJoin(config.peer.maxIncomingPeers)

  val resource: Resource[F, PeerUri] = Resource {
    for {
      fiber   <- serve.compile.drain.start
      address <- localBindAddress.get
    } yield PeerUri.fromTcpAddr(address) -> fiber.cancel
  }
} 
Example 18
Source File: FS2QueueProcess.scala    From aecor   with MIT License 5 votes vote down vote up
package aecor.example.process

import aecor.distributedprocessing.DistributedProcessing.{ Process, RunningProcess }
import cats.effect.Concurrent
import cats.effect.concurrent.Deferred
import cats.implicits._
import fs2._
import fs2.concurrent.Queue
import cats.effect.implicits._

object FS2QueueProcess {
  def create[F[_]: Concurrent, A](
    sources: List[Stream[F, A]]
  ): F[(Stream[F, Stream[F, A]], List[Process[F]])] =
    for {
      queue <- Queue.bounded[F, Stream[F, A]](sources.length)
      processes = sources.map { s =>
        Process {
          Deferred[F, Either[Throwable, Unit]].flatMap { stopped =>
            queue
              .enqueue1(s.interruptWhen(stopped))
              .flatTap(_ => stopped.get)
              .start
              .map { fiber =>
                RunningProcess(fiber.join, stopped.complete(Right(())))
              }
          }
        }
      }
    } yield (queue.dequeue, processes)
} 
Example 19
Source File: CatsEffectSpecs.scala    From cats-effect-testing   with Apache License 2.0 5 votes vote down vote up
package cats.effect.testing.specs2

import cats.effect.{IO, Resource}
import cats.effect.concurrent.{Ref, Deferred}
import cats.implicits._
import org.specs2.mutable.Specification

class CatsEffectSpecs extends Specification with CatsEffect {

  "cats effect specifications" should {
    "run a non-effectful test" in {
      true must beTrue
    }

    "run a simple effectful test" in IO {
      true must beTrue
      false must beFalse
    }

    "run a simple resource test" in {
      true must beTrue
    }.pure[Resource[IO, *]]

    "resource must be live for use" in {
      Resource.make(Ref[IO].of(true))(_.set(false)).map{ 
        _.get.map(_ must beTrue)
      }
    }

    "really execute effects" in {
      "First, this check creates a deferred value.".br

      val deferredValue = Deferred.unsafeUncancelable[IO, Boolean]

      "Then it executes two mutually associated steps:".br.tab

      "forcibly attempt to get the deferred value" in {
        deferredValue.get.unsafeRunTimed(Timeout) must beSome(true)
      }

      "Since specs2 executes steps in parallel by default, the second step gets executed anyway.".br

      "complete the deferred value inside IO context" in {
        deferredValue.complete(true) *> IO.pure(success)
      }

      "If effects didn't get executed then the previous step would fail after timeout.".br
    }

    // "timeout a failing test" in (IO.never: IO[Boolean])
  }
} 
Example 20
Source File: runner.scala    From redis4cats   with Apache License 2.0 5 votes vote down vote up
package dev.profunktor.redis4cats

import cats.effect._
import cats.effect.concurrent.Deferred
import cats.effect.implicits._
import cats.implicits._
import dev.profunktor.redis4cats.effect.Log
import dev.profunktor.redis4cats.hlist._
import java.util.UUID
import scala.concurrent.duration._

object Runner {
  type CancelFibers[F[_]] = Throwable => F[Unit]

  case class Ops[F[_]](
      name: String,
      mainCmd: F[Unit],
      onComplete: CancelFibers[F] => F[Unit],
      onError: F[Unit],
      afterCompletion: F[Unit],
      mkError: () => Throwable
  )

  def apply[F[_]: Concurrent: Log: Timer]: RunnerPartiallyApplied[F] =
    new RunnerPartiallyApplied[F]
}

private[redis4cats] class RunnerPartiallyApplied[F[_]: Concurrent: Log: Timer] {

  def filterExec[T <: HList, R <: HList, S <: HList](ops: Runner.Ops[F])(commands: T)(
      implicit w: Witness.Aux[T, R],
      f: Filter.Aux[R, S]
  ): F[S] = exec[T, R](ops)(commands).map(_.filterUnit)

  def exec[T <: HList, R <: HList](ops: Runner.Ops[F])(commands: T)(implicit w: Witness.Aux[T, R]): F[R] =
    (Deferred[F, Either[Throwable, w.R]], F.delay(UUID.randomUUID)).tupled.flatMap {
      case (promise, uuid) =>
        def cancelFibers[A](fibs: HList)(err: Throwable): F[Unit] =
          joinOrCancel(fibs, HNil)(false).void >> promise.complete(err.asLeft)

        F.debug(s"${ops.name} started - ID: $uuid") >>
          Resource
            .makeCase(ops.mainCmd >> runner(commands, HNil)) {
              case ((fibs: HList), ExitCase.Completed) =>
                for {
                  _ <- F.debug(s"${ops.name} completed - ID: $uuid")
                  _ <- ops.onComplete(cancelFibers(fibs))
                  tr <- joinOrCancel(fibs, HNil)(true)
                  // Casting here is fine since we have a `Witness` that proves this true
                  _ <- promise.complete(tr.asInstanceOf[w.R].asRight)
                } yield ()
              case ((fibs: HList), ExitCase.Error(e)) =>
                F.error(s"${ops.name} failed: ${e.getMessage} - ID: $uuid") >>
                    ops.onError.guarantee(cancelFibers(fibs)(ops.mkError()))
              case ((fibs: HList), ExitCase.Canceled) =>
                F.error(s"${ops.name} canceled - ID: $uuid") >>
                    ops.onError.guarantee(cancelFibers(fibs)(ops.mkError()))
              case _ =>
                F.error(s"Kernel panic: the impossible happened! - ID: $uuid")
            }
            .use(_ => F.unit)
            .guarantee(ops.afterCompletion) >> promise.get.rethrow.timeout(3.seconds)
    }

  // Forks every command in order
  private def runner[H <: HList, G <: HList](ys: H, res: G): F[Any] =
    ys match {
      case HNil                           => F.pure(res)
      case HCons((h: F[_] @unchecked), t) => h.start.flatMap(fb => runner(t, fb :: res))
    }

  // Joins or cancel fibers correspondent to previous executed commands
  private def joinOrCancel[H <: HList, G <: HList](ys: H, res: G)(isJoin: Boolean): F[Any] =
    ys match {
      case HNil => F.pure(res)
      case HCons((h: Fiber[F, Any] @unchecked), t) if isJoin =>
        h.join.flatMap(x => joinOrCancel(t, x :: res)(isJoin))
      case HCons((h: Fiber[F, Any] @unchecked), t) =>
        h.cancel.flatMap(x => joinOrCancel(t, x :: res)(isJoin))
      case HCons(h, t) =>
        F.error(s"Unexpected result: ${h.toString}") >> joinOrCancel(t, res)(isJoin)
    }

} 
Example 21
Source File: Fs2UnaryServerCallListener.scala    From fs2-grpc   with MIT License 5 votes vote down vote up
package org.lyranthe.fs2_grpc
package java_runtime
package server

import cats.effect.{ConcurrentEffect, Effect}
import cats.effect.concurrent.{Deferred, Ref}
import cats.syntax.all._
import io.grpc._

class Fs2UnaryServerCallListener[F[_], Request, Response] private (
    request: Ref[F, Option[Request]],
    isComplete: Deferred[F, Unit],
    val isCancelled: Deferred[F, Unit],
    val call: Fs2ServerCall[F, Request, Response]
)(implicit F: Effect[F])
    extends ServerCall.Listener[Request]
    with Fs2ServerCallListener[F, F, Request, Response] {

  import Fs2UnaryServerCallListener._

  override def onCancel(): Unit = {
    isCancelled.complete(()).unsafeRun()
  }

  override def onMessage(message: Request): Unit = {
    request.access
      .flatMap[Unit] {
        case (curValue, modify) =>
          if (curValue.isDefined)
            F.raiseError(statusException(TooManyRequests))
          else
            modify(message.some).void
      }
      .unsafeRun()

  }

  override def onHalfClose(): Unit =
    isComplete.complete(()).unsafeRun()

  override def source: F[Request] =
    for {
      _ <- isComplete.get
      valueOrNone <- request.get
      value <- valueOrNone.fold[F[Request]](F.raiseError(statusException(NoMessage)))(F.pure)
    } yield value
}

object Fs2UnaryServerCallListener {

  val TooManyRequests: String = "Too many requests"
  val NoMessage: String = "No message for unary call"

  private val statusException: String => StatusRuntimeException = msg =>
    new StatusRuntimeException(Status.INTERNAL.withDescription(msg))

  class PartialFs2UnaryServerCallListener[F[_]](val dummy: Boolean = false) extends AnyVal {

    def apply[Request, Response](
        call: ServerCall[Request, Response],
        options: ServerCallOptions = ServerCallOptions.default
    )(implicit
        F: ConcurrentEffect[F]
    ): F[Fs2UnaryServerCallListener[F, Request, Response]] =
      for {
        request <- Ref.of[F, Option[Request]](none)
        isComplete <- Deferred[F, Unit]
        isCancelled <- Deferred[F, Unit]
        serverCall <- Fs2ServerCall[F, Request, Response](call, options)
      } yield new Fs2UnaryServerCallListener[F, Request, Response](request, isComplete, isCancelled, serverCall)
  }

  def apply[F[_]] = new PartialFs2UnaryServerCallListener[F]
} 
Example 22
Source File: Fs2StreamServerCallListener.scala    From fs2-grpc   with MIT License 5 votes vote down vote up
package org.lyranthe.fs2_grpc
package java_runtime
package server

import cats.effect.concurrent.Deferred
import cats.effect.{ConcurrentEffect, Effect}
import cats.implicits._
import io.grpc.ServerCall
import fs2.concurrent.Queue
import fs2._

class Fs2StreamServerCallListener[F[_], Request, Response] private (
    requestQ: Queue[F, Option[Request]],
    val isCancelled: Deferred[F, Unit],
    val call: Fs2ServerCall[F, Request, Response]
)(implicit F: Effect[F])
    extends ServerCall.Listener[Request]
    with Fs2ServerCallListener[F, Stream[F, ?], Request, Response] {

  override def onCancel(): Unit = {
    isCancelled.complete(()).unsafeRun()
  }

  override def onMessage(message: Request): Unit = {
    call.call.request(1)
    requestQ.enqueue1(message.some).unsafeRun()
  }

  override def onHalfClose(): Unit = requestQ.enqueue1(none).unsafeRun()

  override def source: Stream[F, Request] =
    requestQ.dequeue.unNoneTerminate
}

object Fs2StreamServerCallListener {
  class PartialFs2StreamServerCallListener[F[_]](val dummy: Boolean = false) extends AnyVal {

    def apply[Request, Response](
        call: ServerCall[Request, Response],
        options: ServerCallOptions = ServerCallOptions.default
    )(implicit
        F: ConcurrentEffect[F]
    ): F[Fs2StreamServerCallListener[F, Request, Response]] =
      for {
        inputQ <- Queue.unbounded[F, Option[Request]]
        isCancelled <- Deferred[F, Unit]
        serverCall <- Fs2ServerCall[F, Request, Response](call, options)
      } yield new Fs2StreamServerCallListener[F, Request, Response](inputQ, isCancelled, serverCall)
  }

  def apply[F[_]] = new PartialFs2StreamServerCallListener[F]

} 
Example 23
Source File: Fs2ServerCallListener.scala    From fs2-grpc   with MIT License 5 votes vote down vote up
package org.lyranthe.fs2_grpc
package java_runtime
package server

import cats.effect._
import cats.effect.concurrent.Deferred
import cats.implicits._
import fs2.Stream
import io.grpc.{Metadata, Status, StatusException, StatusRuntimeException}

private[server] trait Fs2ServerCallListener[F[_], G[_], Request, Response] {
  def source: G[Request]
  def isCancelled: Deferred[F, Unit]
  def call: Fs2ServerCall[F, Request, Response]

  private def reportError(t: Throwable)(implicit F: Sync[F]): F[Unit] = {
    t match {
      case ex: StatusException =>
        call.closeStream(ex.getStatus, Option(ex.getTrailers).getOrElse(new Metadata()))
      case ex: StatusRuntimeException =>
        call.closeStream(ex.getStatus, Option(ex.getTrailers).getOrElse(new Metadata()))
      case ex =>
        // TODO: Customize failure trailers?
        call.closeStream(Status.INTERNAL.withDescription(ex.getMessage).withCause(ex), new Metadata())
    }
  }

  private def handleUnaryResponse(headers: Metadata, response: F[Response])(implicit F: Sync[F]): F[Unit] =
    call.sendHeaders(headers) *> call.request(1) *> response >>= call.sendMessage

  private def handleStreamResponse(headers: Metadata, response: Stream[F, Response])(implicit F: Sync[F]): F[Unit] =
    call.sendHeaders(headers) *> call.request(1) *> response.evalMap(call.sendMessage).compile.drain

  private def unsafeRun(f: F[Unit])(implicit F: ConcurrentEffect[F]): Unit = {
    val bracketed = F.guaranteeCase(f) {
      case ExitCase.Completed => call.closeStream(Status.OK, new Metadata())
      case ExitCase.Canceled => call.closeStream(Status.CANCELLED, new Metadata())
      case ExitCase.Error(t) => reportError(t)
    }

    // Exceptions are reported by closing the call
    F.runAsync(F.race(bracketed, isCancelled.get))(_ => IO.unit).unsafeRunSync()
  }

  def unsafeUnaryResponse(headers: Metadata, implementation: G[Request] => F[Response])(implicit
      F: ConcurrentEffect[F]
  ): Unit =
    unsafeRun(handleUnaryResponse(headers, implementation(source)))

  def unsafeStreamResponse(headers: Metadata, implementation: G[Request] => Stream[F, Response])(implicit
      F: ConcurrentEffect[F]
  ): Unit =
    unsafeRun(handleStreamResponse(headers, implementation(source)))
} 
Example 24
Source File: Fs2UnaryClientCallListener.scala    From fs2-grpc   with MIT License 5 votes vote down vote up
package org.lyranthe.fs2_grpc
package java_runtime
package client

import cats.effect._
import cats.effect.concurrent.{Deferred, Ref}
import cats.implicits._
import io.grpc._

class Fs2UnaryClientCallListener[F[_], Response](grpcStatus: Deferred[F, GrpcStatus], value: Ref[F, Option[Response]])(
    implicit F: Effect[F]
) extends ClientCall.Listener[Response] {

  override def onClose(status: Status, trailers: Metadata): Unit =
    grpcStatus.complete(GrpcStatus(status, trailers)).unsafeRun()

  override def onMessage(message: Response): Unit =
    value.set(message.some).unsafeRun()

  def getValue: F[Response] = {
    for {
      r <- grpcStatus.get
      v <- value.get
      result <- {
        if (!r.status.isOk)
          F.raiseError(r.status.asRuntimeException(r.trailers))
        else {
          v match {
            case None =>
              F.raiseError(
                Status.INTERNAL
                  .withDescription("No value received for unary call")
                  .asRuntimeException(r.trailers)
              )
            case Some(v1) =>
              F.pure(v1)
          }
        }
      }
    } yield result
  }
}

object Fs2UnaryClientCallListener {

  def apply[F[_]: ConcurrentEffect, Response]: F[Fs2UnaryClientCallListener[F, Response]] = {
    (Deferred[F, GrpcStatus], Ref.of[F, Option[Response]](none)).mapN((response, value) =>
      new Fs2UnaryClientCallListener[F, Response](response, value)
    )
  }

} 
Example 25
Source File: StartResourceSpec.scala    From kafka-journal   with MIT License 5 votes vote down vote up
package com.evolutiongaming.kafka.journal.util

import cats.effect._
import cats.effect.concurrent.{Deferred, Ref}
import cats.implicits._
import com.evolutiongaming.kafka.journal.IOSuite._
import org.scalatest.funsuite.AsyncFunSuite
import org.scalatest.matchers.should.Matchers

class StartResourceSpec extends AsyncFunSuite with Matchers {

  test("StartResource") {
    val result = for {
      deferred <- Deferred[IO, Unit]
      ref      <- Ref.of[IO, Boolean](false)
      res       = Resource.make(IO.unit)(_ => ref.set(true))
      fiber    <- StartResource(res)(_ => deferred.complete(()) *> IO.never.as(()))
      _        <- deferred.get
      _        <- fiber.cancel
      result   <- ref.get
    } yield {
      result shouldEqual true
    }
    result.run()
  }
} 
Example 26
Source File: GracefulFiberSpec.scala    From kafka-journal   with MIT License 5 votes vote down vote up
package com.evolutiongaming.kafka.journal.util

import cats.effect._
import cats.effect.concurrent.{Deferred, Ref}
import cats.implicits._
import com.evolutiongaming.kafka.journal.IOSuite._
import org.scalatest.funsuite.AsyncFunSuite
import org.scalatest.matchers.should.Matchers

class GracefulFiberSpec extends AsyncFunSuite with Matchers {

  test("GracefulFiber") {
    val result = for {
      deferred <- Deferred[IO, Unit]
      ref      <- Ref.of[IO, Boolean](false)
      fiber    <- GracefulFiber[IO].apply { cancel =>
        Concurrent[IO].start[Unit] {
          val loop = for {
            cancel <- cancel
            _      <- ref.set(cancel)
          } yield {
            if (cancel) ().some else none
          }
          for {
            _ <- deferred.complete(())
            _ <- loop.untilDefinedM
          } yield {}
        }
      }
      _      <- fiber.cancel
      result <- ref.get
    } yield {
      result shouldEqual true
    }
    result.run()
  }
} 
Example 27
Source File: ResourceRegistrySpec.scala    From kafka-journal   with MIT License 5 votes vote down vote up
package com.evolutiongaming.kafka.journal.util

import cats.effect._
import cats.effect.concurrent.{Deferred, Ref}
import cats.implicits._
import cats.{Applicative, Foldable}
import com.evolutiongaming.kafka.journal.IOSuite._
import org.scalatest.funsuite.AsyncFunSuite
import org.scalatest.matchers.should.Matchers

import scala.util.control.NoStackTrace

class ResourceRegistrySpec extends AsyncFunSuite with Matchers {

  val error: Throwable = new RuntimeException with NoStackTrace
  for {
    exitCase <- List(
      ExitCase.complete,
      ExitCase.error(error),
      ExitCase.canceled)
  } yield {

    test(s"ResRegistry releases resources, exitCase: $exitCase") {
      val result = exitCase match {
        case ExitCase.Completed    => testError(none)
        case ExitCase.Canceled     => testCancel
        case ExitCase.Error(error) => testError(error.some)
      }
      result.run()
    }
  }

  private def testError(error: Option[Throwable]) = {
    val n = 3

    def logic(release: IO[Unit]) = {
      ResourceRegistry.of[IO].use { registry =>
        val resource = Resource.make(().pure[IO]) { _ => release }
        val fa = registry.allocate(resource)
        implicit val monoidUnit = Applicative.monoid[IO, Unit]
        for {
          _ <- Foldable[List].fold(List.fill(n)(fa))
          _ <- error.fold(().pure[IO])(_.raiseError[IO, Unit])
        } yield {}
      }
    }

    for {
      ref      <- Ref.of[IO, Int](0)
      fa        = logic(ref.update(_ + 1))
      result   <- fa.redeem(_.some, _ => none)
      releases <- ref.get
    } yield {
      result shouldEqual result
      releases shouldEqual n
    }
  }

  private def testCancel = {
    for {
      released <- Ref.of[IO, Int](0)
      started  <- Deferred[IO, Unit]
      fiber    <- Concurrent[IO].start {
        ResourceRegistry.of[IO].use { registry =>
          val resource = Resource.make(().pure[IO]) { _ => released.update(_ + 1) }
          for {
            _ <- registry.allocate(resource)
            _ <- started.complete(())
            _ <- IO.never.as(())
          } yield {}
        }
      }
      _        <- started.get
      _        <- fiber.cancel
      released <- released.get
    } yield {
      released shouldEqual 1
    }
  }
} 
Example 28
Source File: StartResource.scala    From kafka-journal   with MIT License 5 votes vote down vote up
package com.evolutiongaming.kafka.journal.util

import cats.effect._
import cats.effect.concurrent.Deferred
import cats.effect.implicits._
import cats.implicits._

object StartResource {

  def apply[F[_] : Concurrent, A, B](
    res: Resource[F, A])(
    use: A => F[B]
  ): F[Fiber[F, B]] = {

    res.allocated.bracketCase { case (a, release) =>
      for {
        released <- Deferred[F, Unit]
        fiber    <- Concurrent[F].start {
          use(a).guarantee {
            release.guarantee {
              released.complete(())
            }
          }
        }
      } yield {
        new Fiber[F, B] {
          def cancel = fiber.cancel *> released.get
          def join = fiber.join
        }
      }
    } { case ((_, release), exitCase) =>
      exitCase match {
        case ExitCase.Completed           => ().pure[F]
        case _: ExitCase.Error[Throwable] => release
        case ExitCase.Canceled            => release
      }
    }
  }
} 
Example 29
Source File: TopicCommitTest.scala    From kafka-journal   with MIT License 5 votes vote down vote up
package com.evolutiongaming.kafka.journal.replicator

import cats.data.{NonEmptyMap => Nem}
import cats.implicits._
import cats.effect.{Clock, IO}
import com.evolutiongaming.kafka.journal.IOSuite._
import cats.effect.concurrent.{Deferred, Ref}
import com.evolutiongaming.skafka.{Offset, Partition}
import org.scalatest.funsuite.AsyncFunSuite
import org.scalatest.matchers.should.Matchers

import scala.concurrent.duration._

class TopicCommitTest extends AsyncFunSuite with Matchers{

  test("delayed") {

    def commitOf(
      deferred: Deferred[IO, Unit],
      commitsRef: Ref[IO, List[Nem[Partition, Offset]]])(implicit
      clock: Clock[IO]
    ) = {
      val commit = new TopicCommit[IO] {
        def apply(offsets: Nem[Partition, Offset]) = {
          commitsRef.update { offsets :: _ } *> deferred.complete(())
        }
      }

      TopicCommit.delayed(10.millis, commit)
    }

    def clockOf(ref: Ref[IO, FiniteDuration]): Clock[IO] = {
      new Clock[IO] {
        def realTime(unit: TimeUnit): IO[Long] = monotonic(unit)
        def monotonic(unit: TimeUnit): IO[Long] = ref.get.map { _.toUnit(unit).toLong }
      }
    }

    val result = for {
      commitsRef <- Ref[IO].of(List.empty[Nem[Partition, Offset]])
      deferred   <- Deferred[IO, Unit]
      clockRef   <- Ref[IO].of(0.millis)
      clock       = clockOf(clockRef)
      commit     <- commitOf(deferred, commitsRef)(clock)
      _          <- commit(Nem.of((Partition.min, Offset.min)))
      offsets    <- commitsRef.get
      _           = offsets shouldEqual List.empty
      _          <- clockRef.set(20.millis)
      _          <- commit(Nem.of((Partition.unsafe(1), Offset.unsafe(1))))
      _          <- deferred.get
      offsets    <- commitsRef.get
      _           = offsets shouldEqual List(Nem.of((Partition.min, Offset.min), (Partition.unsafe(1), Offset.unsafe(1))))
    } yield {}
    result.run()
  }
} 
Example 30
Source File: KafkaSingletonTest.scala    From kafka-journal   with MIT License 5 votes vote down vote up
package com.evolutiongaming.kafka.journal.replicator

import cats.data.{NonEmptySet => Nes}
import cats.effect.concurrent.{Deferred, Ref}
import cats.effect.{Concurrent, IO, Resource, Timer}
import cats.implicits._
import com.evolutiongaming.catshelper.Log
import com.evolutiongaming.kafka.journal.IOSuite._
import com.evolutiongaming.skafka.consumer.RebalanceListener
import com.evolutiongaming.skafka.{Partition, TopicPartition}
import com.evolutiongaming.sstream.Stream
import org.scalatest.funsuite.AsyncFunSuite
import org.scalatest.matchers.should.Matchers

import scala.concurrent.duration._

class KafkaSingletonTest extends AsyncFunSuite with Matchers {

  test("allocate & release when partition assigned or revoked") {
    `allocate & release when partition assigned or revoked`[IO]().run()
  }

  private def `allocate & release when partition assigned or revoked`[F[_] : Concurrent : Timer](): F[Unit] = {

    val topic = "topic"

    def consumer(deferred: Deferred[F, RebalanceListener[F]]) = {
      new TopicConsumer[F] {

        def subscribe(listener: RebalanceListener[F]) = deferred.complete(listener)

        def poll = Stream.empty

        def commit = TopicCommit.empty
      }
    }

    def topicPartition(partition: Partition) = TopicPartition(topic, partition)

    val result = for {
      listener  <- Resource.liftF(Deferred[F, RebalanceListener[F]])
      allocated <- Resource.liftF(Ref[F].of(false))
      resource   = Resource.make { allocated.set(true) } { _ => allocated.set(false) }
      singleton <- KafkaSingleton.of(topic, consumer(listener).pure[Resource[F, *]], resource, Log.empty[F])
      listener  <- Resource.liftF(listener.get)
      _         <- Resource.liftF {
        for {
          a <- singleton.get
          _  = a shouldEqual none[Unit]
          a <- allocated.get
          _  = a shouldEqual false
          _ <- listener.onPartitionsAssigned(Nes.of(topicPartition(Partition.max)))
          a <- singleton.get
          _  = a shouldEqual none[Unit]
          a <- allocated.get
          _  = a shouldEqual false
          _ <- listener.onPartitionsAssigned(Nes.of(topicPartition(Partition.min)))
          _ <- Timer[F].sleep(10.millis)
          a <- singleton.get
          _  = a shouldEqual ().some
          a <- allocated.get
          _  = a shouldEqual true
          _ <- listener.onPartitionsRevoked(Nes.of(topicPartition(Partition.max)))
          a <- singleton.get
          _  = a shouldEqual ().some
          a <- allocated.get
          _  = a shouldEqual true
          _ <- listener.onPartitionsRevoked(Nes.of(topicPartition(Partition.min)))
          _ <- Timer[F].sleep(10.millis)
          a <- singleton.get
          _  = a shouldEqual none[Unit]
          a <- allocated.get
          _  = a shouldEqual false
        } yield {}
      }
    } yield {}
    result.use { _ => ().pure[F] }
  }
} 
Example 31
Source File: actors.scala    From actors-cats-effect-fs2   with Apache License 2.0 5 votes vote down vote up
package app

import app.syntax._
import cats.effect.Concurrent
import cats.effect.concurrent.{Deferred, Ref}
import cats.effect.syntax.concurrent._
import cats.syntax.flatMap._
import cats.syntax.functor._
import fs2.concurrent.Queue

object actors {
  def actor[F[_], S, O](
    initialState: S,
    receive: Ref[F, S] => F[O]
  )(implicit F: Concurrent[F]): F[F[O]] =
    for {
      ref <- Ref.of[F, S](initialState)
      queue <- Queue.unbounded[F, Deferred[F, O]]
      fiber <- (for {
        deferred <- queue.dequeue1
        output <- receive(ref)
        _ <- deferred.complete(output)
      } yield ()).foreverM.void.start
      ask = for {
        deferred <- Deferred[F, O]
        _ <- queue.offer1(deferred)
        output <- (fiber.join race deferred.get)
          .collect { case Right(o) => o }
      } yield output
    } yield ask

  def actorWithInput[F[_], S, I, O](
    initialState: S,
    receive: (I, Ref[F, S]) => F[O]
  )(implicit F: Concurrent[F]): F[I => F[O]] =
    for {
      ref <- Ref.of[F, S](initialState)
      queue <- Queue.unbounded[F, (I, Deferred[F, O])]
      fiber <- (for {
        inputAndDeferred <- queue.dequeue1
        (input, deferred) = inputAndDeferred
        output <- receive(input, ref)
        _ <- deferred.complete(output)
      } yield ()).foreverM.void.start
      ask = (input: I) =>
        for {
          deferred <- Deferred[F, O]
          _ <- queue.offer1((input, deferred))
          output <- (fiber.join race deferred.get)
            .collect { case Right(o) => o }
        } yield output
    } yield ask
} 
Example 32
Source File: IOForkInterruptBenchmark.scala    From zio   with Apache License 2.0 5 votes vote down vote up
package zio

import java.util.concurrent.TimeUnit

import cats.effect.concurrent.Deferred
import org.openjdk.jmh.annotations._

import zio.IOBenchmarks._

@State(Scope.Thread)
@BenchmarkMode(Array(Mode.Throughput))
@OutputTimeUnit(TimeUnit.SECONDS)
@Warmup(iterations = 10, time = 3, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 10, time = 3, timeUnit = TimeUnit.SECONDS)
@Fork(1)
@Threads(1)
class IOForkInterruptBenchmark {
  @Param(Array("100"))
  var size: Int = _

  @Benchmark
  def monixForkInterrupt(): Unit = {
    import monix.eval.Task

    def loop(i: Int): monix.eval.Task[Unit] =
      if (i < size) Deferred[Task, Unit].flatMap { p1 =>
        Deferred[Task, Unit].flatMap { p2 =>
          p1.complete(())
            .flatMap(_ => Task.never)
            .guarantee(p2.complete(()))
            .start
            .flatMap(f => p1.get.flatMap(_ => f.cancel.flatMap(_ => p2.get.flatMap(_ => loop(i + 1)))))
        }
      }
      else Task.unit

    loop(0).runSyncUnsafe()
  }

  @Benchmark
  def catsForkInterrupt(): Unit = {
    import cats.effect.IO

    def loop(i: Int): IO[Unit] =
      if (i < size)
        Deferred[IO, Unit].flatMap { p1 =>
          Deferred[IO, Unit].flatMap { p2 =>
            p1.complete(())
              .flatMap(_ => IO.never)
              .guarantee(p2.complete(()))
              .start
              .flatMap(f => p1.get.flatMap(_ => f.cancel.flatMap(_ => p2.get.flatMap(_ => loop(i + 1)))))
          }
        }
      else IO.unit

    loop(0).unsafeRunSync()
  }

  @Benchmark
  def zioForkInterrupt(): Unit = zioForkInterrupt(IOBenchmarks)

  @Benchmark
  def zioTracedForkInterrupt(): Unit = zioForkInterrupt(TracedRuntime)

  private[this] def zioForkInterrupt(runtime: Runtime[Any]): Unit = {
    def loop(i: Int): UIO[Unit] =
      if (i < size) IO.never.fork.flatMap(_.interrupt *> loop(i + 1))
      else IO.unit

    runtime.unsafeRun(loop(0))
  }
}