How can I send a message to my akka actor system's event stream without addressing the message to any actor in particular? - scala

I'm interested in implementing:
1. an akka actor A that sends messages to an event stream;
2. an akka actor L that listens to messages of a certain type that have been published on the event stream.
If possible, I would like to reutilize the actor system's event stream.
I know how to do 2. It is explained here: https://doc.akka.io/docs/akka/2.5/event-bus.html#event-stream
But how can I do 1?
I know how to make A send a message addressed to another actor(Ref), but I do not want to address the message to any particular actor(Ref). I just want the message to appear in the event stream and be picked up by whoever is listening to messages of that type. Is this possible somehow?
A side-question: if I implement 2 as described in https://doc.akka.io/docs/akka/2.5/event-bus.html#event-stream, does the listener know who sent the message?

As per the documentation link that you posted you can publish messages to the EventStream:
system.eventStream.publish(Jazz("Sonny Rollins"))
Message will be delivered to all actors that subscribed themselves to this message type:
system.eventStream.subscribe(jazzListener, classOf[Jazz])
For the subscribers to know the sender, I suggest you define an ActorRef field in your payload and the sending actor can put its self reference in it when publishing the message. NB Defining the sender's ActorRef explicitly in the message type is how the new akka-typed library deals with all actor interactions, so it's a good idea to get used to this pattern.

Related

Akka stream best practice for dynamic Source and Flow controlled by websocket messages

I'm trying to understand what is the best way to implement with akka stream and alpakka the following scenario (simplified):
The frontend opens a websocket connection with the backend
Backend should wait an initialization message with some parameters (for example bootstrapServers, topicName and a transformationMethod that is a string parameter)
Once these informations are in place, backend can start the alpakka consumer to consume from topic topicName from bootstrapServers and applying some transformation to the data based on transformationMethod, pushing these results inside the websocket
Periodically, frontend can send through the websocket messages that changes the transformationMethod field, so that the transformation algorithm of the messages consumed from Kafka can dynamically change, based on the value of transformationMethod provided into the websocket.
I don't understand if it's possible to achieve this on akka stream inside a Graph, especially the dynamic part, both for the initialization of the alpakka consumer and also for the dynamic changing of the transformationMethod parameter.
Example:
Frontend establish connection, and after 10 second it sends trough the socket the following:
{"bootstrapServers": "localhost:9092", "topicName": "topic", "transformationMethod": "PLUS_ONE"}
Because of that, Alpakka consumer is instantiated and starts reading messages from Kafka.
Messages are flowing in Kafka, so it arrives 1 and in the websocket the frontend will receive 2 (because of the PLUS_ONE transformation method, that is probably placed in a map or a via with a Flow), then 2 and so frontend receives 3 and so on.
Then, frontend sends:
{"transformationMethod": "SQUARE"}
So now, from Kafka arrives 3 and the frontend will receive 9, then 4 and so the output will be 16 ecc...
This is more or less the flow of what I would like to obtain.
I am able to create a websocket connection with Alpakka consumer that perform some sort of "static" transformations and push back the result to the websocket, it's straightforward, what I miss is this dynamic part but I'm not sure if i can implement that inside the same graph or if I need more layers (maybe with some Actor that manages the flow and will activate/change the behavior of the Alpakka consumer in real time sending messages?)
Thanks
I would probably tend to implement this by spawning an actor for each websocket, prematerializing a Source which will receive messages from the actor (probably using ActorSource.actorRefWithBackpressure), building a Sink (likely using ActorSink.actorRefWithBackpressure) which adapts incoming websocket messages into control-plane messages (initialization (including the ActorRef associated with the prematerialized source) and transformation changes) and sends them to the actor, and then tying them together using the handleMessagesWithSinkSource on WebsocketUpgrade.
The actor you're spawning would, on receipt of the initialization message, start a stream which is feeding messages to it from Kafka; some backpressure can be fed back to Kafka by having the stream feed messages via an ask protocol which waits for an ack; in order to keep that stream alive, the actor would need to ack within a certain period of time regardless of what the downstream did, so there's a decision to be made around having the actor buffer messages or drop them.

Is batch message sending possible with Sink.actorRefWithAck?

I'm using Akka Streams and I came across Sink.actorRefWithAck. I understand that it sends a message and only tries pulling in another element from the stream when an acknowledgement for the previous message has been received. Is there a way to batch-process messages with this sink? Example: pull five messages and only pull the next five once the first five have been acknowledged. I've thought about something like
source.grouped(5).to(Sink.actorRefWithAck(...))
But that would require the receiver to change to work with sequences, which let's assume is out of the question.
No, that is not possible with Sink.actorRefWithAck() while keeping individual messages being queued in the actor mailbox rather than the entire batch.
One idea to queue up messages in the actor inbox more eagerly would be to use source.mapAsync(n)(ask-actor).to(Sink.ignore). This would send n to the actor and then as soon as the first one gets a response from the actor, it would pull and enqueue a new element.

How I can prioritize mailbox in untyped Actor?

Problem:
Actor process all messages from his mailbox using FIFO strategy.
Let's suppose we want kill an actor sending to him the MyPoisonPill message, actor still handle messages in mailbox until arrive turn of MyPoisonPill.
Question:
How I can prioritize messages in actor mailbox?
UPD:
Let's consider A PoisonPill like my own message, because I am not sure that akka's PoisonPill has or not any priority in mailbox.
There are different strategies about how the messages are delivered. You can create a BoundedPriorityMailbox to have a priority for your messages.
Other type of mailboxes are given in https://doc.akka.io/docs/akka/2.5/mailboxes.html#builtin-mailbox-implementations
An example to implement is given in https://blog.knoldus.com/how-to-create-a-priority-based-mailbox-for-an-actor/

Akka DistributedPubSubMediator at-least-once delivery guarantees for publishing to a topic

I need to have at-least-once delivery guarantees for messages published to a DistributedPubSubMediator topic.
I looked into DistributedPubSubMediator.scala and can see the following in TopicLike trait (Akka 2.4.6):
trait TopicLike extends Actor {
var subscribers = Set.empty[ActorRef]
def defaultReceive: Receive = {
case msg ?
subscribers foreach { _ forward msg }
}
}
However I couldn't find any method to retrieve subscribers set from mediator... It would be great if there was a message request GetTopicSubscribers which would expose this information to mediator clients:
mediator ! GetTopicSubscribers("mytopic")
So after publishing to a topic the publisher could wait for Ack messages from all active subscribers. Is there any other way to accomplish something like that?
It would be great if somehow akka.contrib.pattern.ReliableProxy can be plugged in into DistributedPubSubMediator.
You could get your publisher to ask the mediator for the count of subscribers via a akka.cluster.pubsub.DistributedPubSubMediator.CountSubscribers("myTopic")
Then it just needs to keep a count of how many Ack messages it gets from subscribers.
No need to track actual subscribers or which ones have Acknowledged, when your Ack count reaches the subscriber count you know they have all received it (thanks to Akka at-most-once delivery reliability)
Note however this comment in the source code:
// Only for testing purposes, to poll/await replication
case object Count
final case class CountSubscribers(topic: String)
Suggests perhaps CountSubscribers is not something to rely on too heavily?

Persistent Akka Mailboxes and Losslessness

In Akka, when an actor dies while processing a message (inside onReceive(...) { ... }, that message is lost. Is there a way to guarantee losslessness? Is there a way to configure Akka to always persist messages before sending them to onReceive, so that they can be recovered and replayed when the actor does die?
Perhaps something like a persistent mailbox?
Yes, take a look at Akka Persistence, in particular AtLeastOnceDelivery. This stores messages on the sender side in order to also cover losses during the delivery process, because otherwise the message might not ever reach the destination mailbox.