Packages

  • package root
    Definition Classes
    root
  • package akka
    Definition Classes
    root
  • package actor
    Definition Classes
    akka
  • package typed
    Definition Classes
    actor
  • package delivery
    Definition Classes
    typed
  • object WorkPullingProducerController

    Work pulling is a pattern where several worker actors pull tasks in their own pace from a shared work manager instead of that the manager pushes work to the workers blindly without knowing their individual capacity and current availability.

    Work pulling is a pattern where several worker actors pull tasks in their own pace from a shared work manager instead of that the manager pushes work to the workers blindly without knowing their individual capacity and current availability.

    The WorkPullingProducerController can be used together with ConsumerController to implement the work pulling pattern.

    One important property is that the order of the messages should not matter, because each message is routed randomly to one of the workers with demand. In other words, two subsequent messages may be routed to two different workers and processed independent of each other.

    A worker actor (consumer) and its ConsumerController is dynamically registered to the WorkPullingProducerController via a ServiceKey. It will register itself to the * akka.actor.typed.receptionist.Receptionist, and the WorkPullingProducerController subscribes to the same key to find active workers. In this way workers can be dynamically added or removed from any node in the cluster.

    The work manager (producer) actor will start the flow by sending a WorkPullingProducerController.Start message to the WorkPullingProducerController. The ActorRef in the Start message is typically constructed as a message adapter to map the WorkPullingProducerController.RequestNext to the protocol of the producer actor.

    The WorkPullingProducerController sends RequestNext to the producer, which is then allowed to send one message to the WorkPullingProducerController via the sendNextTo in the RequestNext. Thereafter the producer will receive a new RequestNext when it's allowed to send one more message. It will send a new RequestNext when there are demand from any worker. It's possible that all workers with demand are deregistered after the RequestNext is sent and before the actual messages is sent to the WorkPullingProducerController. In that case the message is buffered and will be delivered when a new worker is registered or when there is new demand.

    The producer and WorkPullingProducerController actors are supposed to be local so that these messages are fast and not lost. This is enforced by a runtime check.

    Many unconfirmed messages can be in flight between the WorkPullingProducerController and each ConsumerController. The flow control is driven by the consumer side, which means that the WorkPullingProducerController will not send faster than the demand requested by the workers.

    Lost messages are detected, resent and deduplicated if needed. This is also driven by the consumer side, which means that the WorkPullingProducerController will not push resends unless requested by the ConsumerController.

    If a worker crashes or is stopped gracefully the unconfirmed messages for that worker will be routed to other workers by the WorkPullingProducerController. This may result in that some messages may be processed more than once, by different workers.

    Until sent messages have been confirmed the WorkPullingProducerController keeps them in memory to be able to resend them. If the JVM of the WorkPullingProducerController crashes those unconfirmed messages are lost. To make sure the messages can be delivered also in that scenario the WorkPullingProducerController can be used with a DurableProducerQueue. Then the unconfirmed messages are stored in a durable way so that they can be redelivered when the producer is started again. An implementation of the DurableProducerQueue is provided by EventSourcedProducerQueue in akka-persistence-typed.

    Instead of using tell with the sendNextTo in the RequestNext the producer can use context.ask with the askNextTo in the RequestNext. The difference is that a reply is sent back when the message has been handled. If a DurableProducerQueue is used then the reply is sent when the message has been stored successfully, but it might not have been processed by the consumer yet. Otherwise the reply is sent after the consumer has processed and confirmed the message.

    It's also possible to use the WorkPullingProducerController and ConsumerController without resending lost messages, but the flow control is still used. This can for example be useful when both consumer and producer are know to be located in the same local ActorSystem. This can be more efficient since messages don't have to be kept in memory in the ProducerController until they have been confirmed, but the drawback is that lost messages will not be delivered. See configuration only-flow-control of the ConsumerController.

    The producerId is used in logging and included as MDC entry with key "producerId". It's propagated to the ConsumerController and is useful for correlating log messages. It can be any String but it's recommended to use a unique identifier of representing the producer.

    If the DurableProducerQueue is defined it is created as a child actor of the WorkPullingProducerController actor. ProducerController actors are created for each registered worker. Those child actors use the same dispatcher as the parent WorkPullingProducerController.

    Definition Classes
    delivery
    Annotations
    @ApiMayChange()
  • Command
  • GetWorkerStats
  • MessageWithConfirmation
  • RequestNext
  • Settings
  • Start
  • WorkerStats

final case class RequestNext[A](sendNextTo: ActorRef[A], askNextTo: ActorRef[MessageWithConfirmation[A]]) extends Product with Serializable

The WorkPullingProducerController sends RequestNext to the producer when it is allowed to send one message via the sendNextTo or askNextTo. Note that only one message is allowed, and then it must wait for next RequestNext before sending one more message.

Source
WorkPullingProducerController.scala
Linear Supertypes
Type Hierarchy
Ordering
  1. Alphabetic
  2. By Inheritance
Inherited
  1. RequestNext
  2. Serializable
  3. Product
  4. Equals
  5. AnyRef
  6. Any
Implicitly
  1. by any2stringadd
  2. by StringFormat
  3. by Ensuring
  4. by ArrowAssoc
  1. Hide All
  2. Show All
Visibility
  1. Public
  2. Protected

Instance Constructors

  1. new RequestNext(sendNextTo: ActorRef[A], askNextTo: ActorRef[MessageWithConfirmation[A]])

Value Members

  1. final def !=(arg0: Any): Boolean
    Definition Classes
    AnyRef → Any
  2. final def ##: Int
    Definition Classes
    AnyRef → Any
  3. def +(other: String): String
    Implicit
    This member is added by an implicit conversion from RequestNext[A] toany2stringadd[RequestNext[A]] performed by method any2stringadd in scala.Predef.
    Definition Classes
    any2stringadd
  4. def ->[B](y: B): (RequestNext[A], B)
    Implicit
    This member is added by an implicit conversion from RequestNext[A] toArrowAssoc[RequestNext[A]] performed by method ArrowAssoc in scala.Predef.
    Definition Classes
    ArrowAssoc
    Annotations
    @inline()
  5. final def ==(arg0: Any): Boolean
    Definition Classes
    AnyRef → Any
  6. final def asInstanceOf[T0]: T0
    Definition Classes
    Any
  7. val askNextTo: ActorRef[MessageWithConfirmation[A]]
  8. def clone(): AnyRef
    Attributes
    protected[lang]
    Definition Classes
    AnyRef
    Annotations
    @throws(classOf[java.lang.CloneNotSupportedException]) @HotSpotIntrinsicCandidate() @native()
  9. def ensuring(cond: (RequestNext[A]) => Boolean, msg: => Any): RequestNext[A]
    Implicit
    This member is added by an implicit conversion from RequestNext[A] toEnsuring[RequestNext[A]] performed by method Ensuring in scala.Predef.
    Definition Classes
    Ensuring
  10. def ensuring(cond: (RequestNext[A]) => Boolean): RequestNext[A]
    Implicit
    This member is added by an implicit conversion from RequestNext[A] toEnsuring[RequestNext[A]] performed by method Ensuring in scala.Predef.
    Definition Classes
    Ensuring
  11. def ensuring(cond: Boolean, msg: => Any): RequestNext[A]
    Implicit
    This member is added by an implicit conversion from RequestNext[A] toEnsuring[RequestNext[A]] performed by method Ensuring in scala.Predef.
    Definition Classes
    Ensuring
  12. def ensuring(cond: Boolean): RequestNext[A]
    Implicit
    This member is added by an implicit conversion from RequestNext[A] toEnsuring[RequestNext[A]] performed by method Ensuring in scala.Predef.
    Definition Classes
    Ensuring
  13. final def eq(arg0: AnyRef): Boolean
    Definition Classes
    AnyRef
  14. final def getClass(): Class[_ <: AnyRef]
    Definition Classes
    AnyRef → Any
    Annotations
    @HotSpotIntrinsicCandidate() @native()
  15. final def isInstanceOf[T0]: Boolean
    Definition Classes
    Any
  16. final def ne(arg0: AnyRef): Boolean
    Definition Classes
    AnyRef
  17. final def notify(): Unit
    Definition Classes
    AnyRef
    Annotations
    @HotSpotIntrinsicCandidate() @native()
  18. final def notifyAll(): Unit
    Definition Classes
    AnyRef
    Annotations
    @HotSpotIntrinsicCandidate() @native()
  19. def productElementNames: Iterator[String]
    Definition Classes
    Product
  20. val sendNextTo: ActorRef[A]
  21. final def synchronized[T0](arg0: => T0): T0
    Definition Classes
    AnyRef
  22. final def wait(arg0: Long, arg1: Int): Unit
    Definition Classes
    AnyRef
    Annotations
    @throws(classOf[java.lang.InterruptedException])
  23. final def wait(arg0: Long): Unit
    Definition Classes
    AnyRef
    Annotations
    @throws(classOf[java.lang.InterruptedException]) @native()
  24. final def wait(): Unit
    Definition Classes
    AnyRef
    Annotations
    @throws(classOf[java.lang.InterruptedException])

Deprecated Value Members

  1. def finalize(): Unit
    Attributes
    protected[lang]
    Definition Classes
    AnyRef
    Annotations
    @throws(classOf[java.lang.Throwable]) @Deprecated
    Deprecated

    (Since version 9)

  2. def formatted(fmtstr: String): String
    Implicit
    This member is added by an implicit conversion from RequestNext[A] toStringFormat[RequestNext[A]] performed by method StringFormat in scala.Predef.
    Definition Classes
    StringFormat
    Annotations
    @deprecated @inline()
    Deprecated

    (Since version 2.12.16) Use formatString.format(value) instead of value.formatted(formatString), or use the f"" string interpolator. In Java 15 and later, formatted resolves to the new method in String which has reversed parameters.

  3. def [B](y: B): (RequestNext[A], B)
    Implicit
    This member is added by an implicit conversion from RequestNext[A] toArrowAssoc[RequestNext[A]] performed by method ArrowAssoc in scala.Predef.
    Definition Classes
    ArrowAssoc
    Annotations
    @deprecated
    Deprecated

    (Since version 2.13.0) Use -> instead. If you still wish to display it as one character, consider using a font with programming ligatures such as Fira Code.

Inherited from Serializable

Inherited from Product

Inherited from Equals

Inherited from AnyRef

Inherited from Any

Inherited by implicit conversion any2stringadd fromRequestNext[A] to any2stringadd[RequestNext[A]]

Inherited by implicit conversion StringFormat fromRequestNext[A] to StringFormat[RequestNext[A]]

Inherited by implicit conversion Ensuring fromRequestNext[A] to Ensuring[RequestNext[A]]

Inherited by implicit conversion ArrowAssoc fromRequestNext[A] to ArrowAssoc[RequestNext[A]]

Ungrouped