All Downloads are FREE. Search and download functionalities are using the official Maven repository.

endless.runtime.akka.ShardingCommandSender.scala Maven / Gradle / Ivy

The newest version!
package endless.runtime.akka

import akka.cluster.sharding.typed.scaladsl.{ClusterSharding, EntityTypeKey}
import akka.util.Timeout
import cats.effect.kernel.Async
import cats.syntax.applicative.*
import cats.syntax.flatMap.*
import cats.syntax.show.*
import cats.~>
import endless.core.entity.EntityNameProvider
import endless.core.protocol.{CommandSender, EntityIDEncoder, OutgoingCommand}
import endless.runtime.akka.data.{Command, Reply}
import org.typelevel.log4cats.Logger

/** Implementation of [[CommandSender]] for Akka cluster sharding
  *
  * Retrieves the entity ref and asks the command, then decodes the reply and lifts it into `F`
  *
  * @param sharding
  *   Akka cluster sharding extension
  * @param askTimeout
  *   Akka ask timeout
  * @param idEncoder
  *   entity ID encoder
  * @param nameProvider
  *   entity name provider
  * @tparam F
  *   context, supports [[Async]] for bridging with `Future`
  * @tparam ID
  *   entity ID
  */
private[akka] final class ShardingCommandSender[F[_]: Logger, ID](implicit
    sharding: ClusterSharding,
    askTimeout: Timeout,
    idEncoder: EntityIDEncoder[ID],
    nameProvider: EntityNameProvider[ID],
    F: Async[F]
) extends CommandSender[F, ID] {
  def senderForID(id: ID): OutgoingCommand[*] ~> F =
    new (OutgoingCommand[*] ~> F) {
      def apply[A](fa: OutgoingCommand[A]): F[A] = {
        val encodedID = idEncoder.encode(id)
        F.fromFuture {
          Logger[F].debug(
            show"Sending command to ${nameProvider()} entity $encodedID"
          ) >> F
            .delay {
              sharding.entityRefFor(
                EntityTypeKey[Command](nameProvider()),
                encodedID
              ) ? Command(encodedID, fa.payload)
            }
        } >>= { case Reply(payload) =>
          Logger[F].debug(
            show"Got reply from ${nameProvider()} entity $encodedID"
          ) >> fa.replyDecoder.decode(payload).pure[F]
        }
      }
    }
}

object ShardingCommandSender {
  implicit def apply[F[_]: Logger, ID](implicit
      sharding: ClusterSharding,
      askTimeout: Timeout,
      idEncoder: EntityIDEncoder[ID],
      nameProvider: EntityNameProvider[ID],
      F: Async[F]
  ): CommandSender[F, ID] = new ShardingCommandSender
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy