Akka remoting: Remote subscribed event listener custom serialising a Watch message - scala

I have the following remote actor set up.
actorSystem.actorSelection(remoteConfig.getString("/myEventListener")).resolveOne().map{ar =>
actorSystem.eventStream.subscribe(ar, classOf[MyEvent])
}
I also have my own custom serialization. The issue is that this gets sent a Watch message which has the following signature:
private[akka] final case class Watch(watchee: InternalActorRef, watcher: InternalActorRef) extends SystemMessage
Which is not so straight forward to serialize. Any suggestions on how to proceed on this one? Sending a remote message with references to InternalActorRef seems a bit of an odd one.
And to note I use other remote actors directly (not as event listeners), these dont get sent the Watch message:
val emailService = actorSystem.actorSelection(remoteConfig.getString("/emailCommandHandler"))

Related

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 TCP IO sends me connect message twice

I have a simple client server program
The server listens as follows
val manager = IO(Tcp)
manager ! Bind(self, myAddress,1,options)
Then in receive loop
override def receive = {
case b # Bound(addr) =>
{
log.info("bound")
myAddress = addr
bBound = true
}
case c # Connected(remoteAddress,localAddress) =>
log.info("Client Connected. Remote: {} Local: {}", remoteAddress, localAddress)
myAPAddress = remoteAddress
remoteConnection = sender()
remoteConnection ! Register(self,keepOpenOnPeerClosed=true)
//first thing to do is to register yourself with a lookup
mLookupManager ! AddMe(myAddress, this.context.self.path)
However the connect message is being received twice.
The server actor is not getting restarted as I have overloaded preRestart and it is not getting called. The problem is that the lookup manager looks up and if finds an actorpath with same socket address then sends a poison pill to it. And then adds new actor to it.
However In this case it kills the same actor and adds it's actorpath
Why would I get the connect message twice? Any clue?
When Bind has successfully completed (you got Bound back) the server actor it will get a Connect message for every new connection that is made to the socket.
The common pattern is to let the Connect message trigger creation of a new actor who will be responsible for interacting with that specific client, rather than having the "server" actor doing the interaction.
See the docs here for a sample that does exactly that: http://doc.akka.io/docs/akka/2.4.14/scala/io-tcp.html#Accepting_connections

MassTransit Send only

I am implementing a Service Bus and having a look at MassTransit. My pattern is not Publish/Subscribe but Sender/Receiver where the Receiver can be offline and came back online later.
Right now I am starting to write my tests to verify that MassTransit succesfully deliver the message using the following code:
bus = ServiceBusFactory.New(sbc =>
{
sbc.UseMsmq(
cfg =>
{
cfg.Configurator.UseJsonSerializer();
cfg.Configurator.ReceiveFrom("msmq://localhost/my_queue");
cfg.VerifyMsmqConfiguration();
});
});
Then I grab the bus and publish a message like this:
bus.Publish<TMessage>(message);
As I can notice from MSMQ, two queues are created and the message is sent cause Mass Transit does not raise any error but I cannot find any message in the queue container.
What am I doing wrong?
Update
Reading the Mass Transit newsgroup I found out that in a scenario of Sender/Receiver where the receiver can come online at any time later, the message can be Send using this code:
bus.GetEndpoint(new Uri("msmq://localhost/my_queue")).Send<TMessage>(message);
Again in my scenario I am not writing a Publisher/Subscriber but a Sender/Receiver.
First, to send, you can use a simple EndpointCacheFactory instead of a ServiceBusFactory...
var cache = EndpointCacheFactory.New(x => x.UseMsmq());
From the cache, you can retrieve an endpoint by address:
var endpoint = cache.GetEndpoint("msmq://localhost/queue_name");
Then, you can use the endpoint to send a message:
endpoint.Send(new MyMessage());
To receive, you would create a bus instance as you specified above:
var bus = ServiceBusFactory.New(x =>
{
x.UseMsmq();
x.ReceiveFrom("msmq://localhost/queue_name");
x.Subscribe(s => s.Handler<MyMessage>(x => {});
});
Once your receiver process is complete, call Dispose on the IServiceBus instance. Once your publisher is shutting down, call Dispose on the IEndpointCache instance.
Do not dispose of the individual endpoints (IEndpoint) instances, the cache keeps them available for later use until it is disposed.

DistributedPubSubMediator Subscription via Proxy Actor not working

My colleague and I have been puzzled with the different behaviour the DistributedPubSubMediator has for subscribing/unsubscribing directly or via a proxy Actor. We put together a test to show the different result below.
From our understanding, the ActorRef.forward should pass in the original sender, hence whether the message is sent directly to the Mediator or via a proxy Actor should not matter. Ie. http://www.scala-lang.org/api/current/index.html#scala.actors.ActorRef.
To work around, we have to extend the DIstributedPubSubMediator class and include the logic DistributedPubSubMediator object already provides. Ideally, we'd prefer to use the object directly and revert our code.
This seems like a bug. Does anyone know the underlying reason for this unusual behaviour? Please help...
[22-Oct-2013] Test is updated based on Roland's answer (Thank you) and added expectMsgType on SubscriberAck and UnsubscribeAck. We now receive the SubscribeAck, but strangely not the UnSubscribeAck. It is not a major issue but we would like to know why.
Another question, if we may ask altogether, is whether it is good practice to Subscribe remote actors to the DistributedPubSubMediator via proxy Actor running in the same ActorSystem?
At the moment we have:
The subscribing App discovers the publishing App (in non-Akka-way) and gets Cluster address.
The remote subscriber uses this address and the known proxy actor's path to send Identity request.
The remote subscriber gets the ActorIdentity response and then Subscribes/Unsubscribes via this (remote) proxy.
On the publisher App Subscribe/Unsubscribe messages are forwarded to the DistributedPubSubMediator and it is used to publish subsequent business messages.
We are not joining the Cluster as per Akka Reactor pubsub chat client example (ie. only using the DistributedPubSubMediator to publish) because we need to handle Failover on the Publisher side.
[5-Nov-2013] Added a test on Send message. It does not seem to work and we haven't figured it out yet.
package star.common.pubsub
import org.scalatest.{BeforeAndAfterAll, FunSuite}
import org.junit.runner.RunWith
import akka.contrib.pattern.DistributedPubSubExtension
import akka.contrib.pattern.DistributedPubSubMediator._
import akka.testkit.TestKit
import akka.actor.{Actor, ActorSystem, ActorRef, Props}
import scala.concurrent.duration._
import com.typesafe.config.ConfigFactory
object MediatorTest {
val config = ConfigFactory.parseString(s"""
akka.actor.provider="akka.cluster.ClusterActorRefProvider"
akka.remote.netty.tcp.port=0
akka.extensions = ["akka.contrib.pattern.DistributedPubSubExtension"]
""")
}
#RunWith(classOf[org.scalatest.junit.JUnitRunner])
class MediatorTest extends TestKit(ActorSystem("test", MediatorTest.config)) with FunSuite {
val mediator = DistributedPubSubExtension(system).mediator
val topic = "example"
val message = "Published Message"
// val joinAddress = Cluster(system).selfAddress
// Cluster(system).join(joinAddress)
test("Direct subscribe to mediator") {
mediator.!(Subscribe(topic, testActor))(testActor)
expectMsgType[SubscribeAck](5 seconds)
mediator.!(Publish(topic, message))(testActor)
expectMsg(2 seconds, message)
mediator.!(Unsubscribe(topic, testActor))(testActor)
expectMsgType[UnsubscribeAck](5 seconds)
mediator ! Publish(topic, message)
expectNoMsg(2 seconds)
}
test("Subscribe to mediator via proxy") {
class Proxy extends Actor {
override def receive = {
case subscribe: Subscribe =>
mediator forward subscribe
case unsubscribe: Unsubscribe =>
mediator forward unsubscribe
case publish: Publish =>
mediator.!(publish)
}
}
val proxy = system.actorOf(Props(new Proxy), "proxy")
proxy.!(Subscribe(topic,testActor))(testActor)
expectMsgType[SubscribeAck](2 seconds)
proxy ! Publish(topic, message)
expectMsg(5 seconds, message)
proxy.!(Unsubscribe(topic,testActor))(testActor)
expectMsgType[UnsubscribeAck](5 seconds)
proxy ! Publish(topic, message)
expectNoMsg(5 seconds)
}
test("Send message to address") {
val testActorAddress = testActor.path.toString
// val system2 = ActorSystem("test", MediatorTest.config)
// Cluster(system2).join(joinAddress)
mediator.!(Subscribe(topic, testActor))(testActor)
expectMsgType[SubscribeAck](5 seconds)
println(testActorAddress) // akka://test/system/testActor1
mediator.!(Publish(topic, message))(testActor)
expectMsg(2 seconds, message)
mediator ! Send(testActorAddress, message, false)
expectMsg(5 seconds, message)
}
}
Two things:
whether or not you use forward does not matter much, since you do not have a useful sender in scope in your test procedure (you are not mixing in ImplicitSender); but this is not the problem
you are not forwarding the Publish message, which is why it does not publish the message

Akka timeouts starting event handlers

When I run my app using akka, it fails with the following exception:
Event Handler specified in config can't be loaded [com.despegar.hasp.impl.DummyLogEventHandler] due to [a06c8d75-0f07-40db-883a-16dc2914934bakka.event.Logging$LoggerInitializationException: Logger log1-DummyLogEventHandler did not respond with LoggerInitialized, sent instead [TIMEOUT]
DummyLogEventHandler is defined as:
class DummyLogEventHandler extends Actor {
def receive = {
case InitializeLogger(_) => sender ! LoggerInitialized
case Error(cause, logSource, logClass, message) =>
case Warning(logSource, logClass, message) =>
case Info(logSource, logClass, message) =>
case Debug(logSource, logClass, message) =>
}
}
My configuration has the following lines:
event-handlers = ["my.app.DummyLogEventHandler"]
event-handler-startup-timeout = 15s
But I've also tried with the default logger:
event-handlers = []
and with slf4j (my app is using the logback backend and logging works ok):
event-handlers = ["akka.event.slf4j.Slf4jEventHandler"]
Neither of those event-handlers nor incrementing the timeout to 60 seconds have worked so far. Moreover, the timeout is thrown sporadically. When I ran a test suite, the exception is thrown in different tests every time.
Can you help me find a solution?
Thanks,
Alex.
Try to set a larger timeout for the logger initialization :
For example in the conf file :
akka {logger-startup-timeout = 25s }
checkout the doc
http://doc.akka.io/docs/akka/snapshot/general/configuration.html
After discussion on akka-user the following was found.
This problem is a symptom of configuring the akka.actor.default-dispatcher to be of type = BalancingDispatcher, which cannot work, see the docs for that dispatcher type:
All the actors share a single Mailbox that they get their messages from.
It is assumed that all actors using the same instance of this dispatcher can process all messages that have been sent to one of the actors; i.e. the actors belong to a pool of actors, and to the client there is no guarantee about which actor instance actually processes a given message.
Sharability: Actors of the same type only
In my case, adding the timeout setting in conf does not work, but setting system property directly like below works.
System.setProperty("akka.logger-startup-timeout", "30s")