How to limit the number of actors of a particular type? - scala

I've created an actor to send messages to a chat server. However, the chat server only permits 5 connections per user. If I hammer my scala server I get error messages because my chat clients get disconnected.
So how can I configure akka so that my XmppSenderActors only use a maximum of 5 threads? I don't want to restrict the rest of the actor system, only this object (at the path /XmppSenderActor/).
I'm trying this config since I think it's the dispatcher I need to configure, but I'm not sure:
akka.actor.deployment {
/XmppSenderActor {
dispatcher = xmpp-dispatcher
}
xmpp-dispatcher {
fork-join-executor.parallelism-min = 2
fork-join-executor.parallelism-max = 3
}
}
This gives me an error though: akka.ConfigurationException: Dispatcher [xmpp-dispatcher] not configured for path akka://sangria-server/user/XmppSenderActor

I would probably try to configure a Router instead.
http://doc.akka.io/docs/akka/2.0/scala/routing.html
A dispatcher seems to deal with sending messages to the inbox rather than the actual number or Actor targets.
That configuration in particular could work for you:
akka.actor.deployment {
/router {
router = round-robin
nr-of-instances = 5
}
}
The nr-of-instances will create 5 childrens from the get going and therefore fill your needs.
You might need to find the right Router implementation though.

Related

What is best way to run periodic consumer for redis or kafka in Ktor backend?

I'm trying to use Ktor for my new backend, and I have a question about how can I launch periodic consumer for kafka or redis inside Ktor backend application.
In very simple way, I thought that I make a single backend application configurable to enable routing and consuming, thus some of instance will support both, and some of instance will support only routing to ensure availability.
But, I'm not sure how can I trigger consumer application from ktor. From the code I tested with this,
fun main() {
embeddedServer(Netty, port = 8080, host = "127.0.0.1") {
configureDependencyInjection()
configureRouting()
configureSecurity()
configureSerialization()
configureExceptionHandling()
configureMonitoring()
consumerStarting() // this is consumer starting.
}.start(wait = true)
}
#OptIn(ExperimentalTime::class)
fun Application.consumerStarting() {
CoroutineScope(Dispatchers.IO).launch {
// todo: make this in to rule activator initializer
println("TEST")
delay(3.seconds)
consumerStarting()
}
}
And, when I tested this, I can see that "TEST" will be printed every 3 seconds.
Similar to this way, I thought that I can start monitoring instances from Application.consumerStarting() (e.g. periodically fetch stream from redis, consume it we coroutine, etc.).
But I'm not sure it is right way because I cannot find any references for this situation with Ktor.
Any comment will be welcome.

How to get number of requests waitinng to be processed when deployed a vertx httpserver as worker verticle?

Is there any other way to get a number of requests waiting to be processed by worker threads when deploying an HTTP server as worker verticle? I need an alternative for https://vertx.io/docs/vertx-dropwizard-metrics/java/#_pool_metrics.
You can try to utilize Asynchronous Counters which you can increment whenever you send an event to specific address on event bus and then decrement when verticle is done processing (or have just picked up an event). If you have lot of verticles and don't want to modify each of them, you can set outbound interceptor:
vertx.eventBus().addOutboundInterceptor(deliveryContext -> {
//you can validate if the address is what you are looking for
if (deliveryContext.message().address().equalsIgnoreCase("http event")) {
//increment counter
}
deliveryContext.next();
});
if you have a lot of addresses to cover you can always add some specific header to the message and then look for it in the interceptor but that would mean you have to modify each .send() call in worst case scenario:
vertx.eventBus().addOutboundInterceptor(deliveryContext -> {
//looking for specific header
if (deliveryContext.message().headers().contains("incrementCounterHeader")) {
//increment counter
}
deliveryContext.next();
});
//later in code
vertx.eventBus().send("http event", message,
new DeliveryOptions().addHeader("incrementCounterHeader", "somevalue"));
last but not least if you decide to use async counter you might want to propagate message only .onComplete() or .onSuccess(), depends on your business logic.
Hope this will help!

Formulate correct scenario phrase

I would like to know, if the following Gherkin phrase correspond to BDD rules:
final class KafkaSpec extends BddSpec {
feature("Kafka distribution to SAP server via websocket") {
scenario("Kafka consumer does not receive messages from Kafka server") {
Given("Kafka server is NOT active")
When("consumer client get started")
val ex = SenderActor.run
Then("print message `Failed to connect to Kafka`")
ex.failed map { ex =>
assertThrows[ConnectException](ex)
}
}
scenario("Kafka consumer receives messages from Kafka server") {
Given("Kafka server is ACTIVE")
When("consumer client get started")
Then("print message `Successfully connected to Kafka`")
succeed
}
}
}
Do I use the right tense? Do I use the Given-When-Then correctly?
The Givens (contexts) are fine; we normally use either continuous present or past tense for those:
Given the kafka server is active <-- continuous present
Given the kafka server was started <-- past tense
For the Whens (events), it's better if you can use an active voice. Active voice starts with who did it. Who started the server? (I've corrected the English a bit here too.)
When the consumer client was started <-- passive voice
When our consumer starts their client <-- active voice
For the Thens (outcomes), I really like the word "should". It encourages people to question it; should it really happen? Now? In this release? Is there any context for which this shouldn't happen or something different should happen? Should it still happen, or has this scenario changed?
Then the consumer interface should print the message, `Successfully connected to Kafka`.
One other thing though: the detail in that last step feels a bit too much to me. If the message changed, you'd have to change it everywhere. Instead I keep that in the code (you can abstract the step out) and would say something like:
Then the interface should tell the consumer that the connection was successful.
This is something we usually call "declarative over imperative". It's also OK to have the passive voice here:
Then the consumer should be told that the connection was successful.
Using the word "should" also helps differentiate between the outcomes of one scenario and the givens of another; often these overlap with an outcome forming the context for another scenario:
Given Priscilla has an account
When she enters her username and password correctly
Then she should be on her home page.
Given Priscilla is on her home page...
I wrote more about tenses and language of BDD here, where you'll also find tons of other resources for new BDDers under the BDD category.

Akka: send error from routee back to caller

In my project, I created UserRepositoryActor which create their own router with 10 UserRepositoryWorkerActor instances as routee, see hierarchy below:
As you see, if any error occur while fetching data from database, it will occur at worker.
Once I want to fetch user from database, I send message to UserRepositoryActor with this command:
val resultFuture = userRepository ? FindUserById(1)
and I set 10 seconds for timeout.
In case of network connection has problem, UserRepositoryWorkerActor immediately get ConnectionException from underlying database driver and then (what I think) router will restart current worker and send FindUserById(1) command to other worker that available and resultFuture will get AskTimeoutException after 10 seconds passed. Then some time later, once connection back to normal, UserRepositoryWorkerActor successfully fetch data from database and then try to send result back to the caller and found that resultFuture was timed out.
I want to propagate error from UserRepositoryWorkerActor up to the caller immediately after exception occur, so that will prevent resultFuture to wait for 10 seconds and stop UserRepositoryWorkerActor to try to fetch data again and again.
How can I do that?
By the way, if you have any suggestions to my current design, please suggest me. I'm very new to Akka.
Your assumption about Router resending the message is wrong. Router has already passed the message to routee and it doesnt have it any more.
As far as ConnectionException is concerned, you could wrap in a scala.util.Try and send response to sender(). Something like,
Try(SomeDAO.getSomeObjectById(id)) match {
case Success(s) => sender() ! s
case Failure(e) => sender() ! e
}
You design looks correct. Having a router allows you to distribute work and also to limit number of concurrent workers accessing the database.
Option 1
You can make your router watch its children and act accordingly when they are terminated. For example (taken from here):
import akka.routing.{ ActorRefRoutee, RoundRobinRoutingLogic, Router }
class Master extends Actor {
var router = {
val routees = Vector.fill(5) {
val r = context.actorOf(Props[Worker])
context watch r
ActorRefRoutee(r)
}
Router(RoundRobinRoutingLogic(), routees)
}
def receive = {
case w: Work =>
router.route(w, sender())
case Terminated(a) =>
router = router.removeRoutee(a)
val r = context.actorOf(Props[Worker])
context watch r
router = router.addRoutee(r)
}
}
In your case you can send some sort of a failed message from the repository actor to the client. Repository actor can maintain a map of worker ref to request id to know which request failed when worker terminates. It can also record the time between the start of the request and actor termination to decide whether it's worth retrying it with another worker.
Option 2
Simply catch all non-fatal exceptions in your worker actor and reply with appropriate success/failed messages. This is much simpler but you might still want to restart the worker to make sure it's in a good state.
p.s. Router will not restart failed workers, neither it will try to resend messages to them by default. You can take a look at supervisor strategy and Option 1 above on how to achieve that.

MassTransit Subscriptions and Receiving Own Messages

I am trying to implement a proof of concept service bus using MassTransit. I have three applications which need to communicate changes of a common entity type between each other. So when the user updates the entity in one application, the other two are notified.
Each application is configured as follows with their own queue:
bus = ServiceBusFactory.New(sbc =>
{
sbc.UseMsmq();
sbc.VerifyMsmqConfiguration();
sbc.ReceiveFrom("msmq://localhost/app1_queue");
sbc.UseSubscriptionService("msmq://localhost/subscription");
sbc.UseControlBus();
sbc.Subscribe(subs =>
{
subs.Handler<IMessage1>(IMessage1_Received);
});
});
There is also a subscription service application configured as follows:
subscriptionBus = ServiceBusFactory.New(sbc =>
{
sbc.UseMsmq();
sbc.VerifyMsmqConfiguration();
sbc.ReceiveFrom("msmq://localhost/subscription");
});
var subscriptionSagas = new InMemorySagaRepository<SubscriptionSaga>();
var subscriptionClientSagas = new InMemorySagaRepository<SubscriptionClientSaga>();
subscriptionService = new SubscriptionService(subscriptionBus, subscriptionSagas, subscriptionClientSagas);
subscriptionService.Start();
The problem is that when one of the applications publishes a message, all three applications receive it (including the original sender).
Is there any way to avoid this (without resorting to adding the application name to the message)?
Thanks,
G
So MassTransit is a pub/sub system. If you publish a message, everyone registered to receive it will. If you need only some endpoints to receive it, then you really need to directly send. It's just how this works.
You could include the source in your message and discard messages that aren't of interest to you. If you implement the Consumes.Accept interface, I think the Accept method would allow you to do so easily without mixing that into the normal consumption code.