I'm working on an Azure Service Fabric application here where I have certain actors that need to receive pings/hooks from other services on demand. The application is a sort of event distribution engine that is intended to work something like this:
An event router actor that can take an event in and then take care of distributing that event to all subscribers of that event type.
0..N event subscription actors that somehow need to inform the router what type of events they wish to subscribe to and how they want them delivered (sync or async).
When the event router actor receives an event of the type MyEvent, it will identify what subscribers are listening and how they want the event delivered. For asynchronous delivery, a message will be popped in an Azure Service Bus topic. For synchronous delivery though, the router actor will invoke the subscription method on the subscribing actors directly, awaiting their response.
Most of this is fairly straight forward, but I'm not entirely sure how I'm going to pull off synchronous delivery of these events. I don't want the event router actor to in any way be aware of any internals in the actors subscribing to events - yet with the current ActorProxy implementations and similar, having access to the interfaces are required to invoke methods on other actors.
Say I subscribe to an event type, informing the event router that my address is fabric:/MyApp/MyEventSubscriberActor and that I want to subscribe to MyEvent. Is there any sensible way within the Service Fabric APIs I can programatically invoke a method on that actor without (for instance OnEventAsync(MyEvent ev) using the ActorProxy.Create<IMyEventSubscriberActor>() method? The source code of these APIs doesn't seem to be publicly available, so I have no direct way of checking how this is done under the hood.
The event subscription actor can implement an event subscription interface that contains an "event-available" method. It can pass that interface to an "subscribe-to-event" method on the event router actor interface.
The event router actor interface can keep a reference to the subscription interface as part of its state. When the event of interest to the subscriber occurs, it can call the "event-available" method on the interface that it received and saved earlier. All of this can be done without explicitly creating an actor proxy to communicate with the event subscription actor (the actors serialization infrastructure does this under the hood).
Here's a very basic example that omits the event type, assumes just one subscriber etc., but should give you an idea of the technique.
Interfaces:
interface IEventRouter : IActor
{
void Subscribe(IEventSubscriber subscriber);
}
interface IEventSubscriber : IActor
{
void EventAvailable();
}
Event subscriber code:
class EventSubscriber : Actor, IEventSubscriber
{
void SubscribeToEvent()
{
IEventRouter router = ActorProxy.Create<IEventRouter>("fabric:/MyApp/MyEventRouterActor");
router.Subscribe(this);
}
public void EventAvailable()
{
// Process the event
}
}
Event router code:
// Define actor state
[DataContract]
class RouterState
{
[DataMember]
public IEventSubscriber Subscriber;
}
// Define actor
class EventRouter : Actor<RouterState>, IEventRouter
{
public void Subscribe(IEventSubscriber subscriber)
{
this.State.Subscriber = subscriber;
}
void OnEventAvailable()
{
this.State.Subscriber.EventAvailable();
}
}
Related
We are using Azure Service Fabric and are using actors to model specific devices, using the id of the device as the ActorId. Service Fabric will instantiate a new actor instance when we request an actor for a given id if it is not already instantiated, but I cannot seem to find an api that allows me to query if a specific device id already has an instantiated actor.
I understand that there might be some distributed/timing issues in obtaining the point-in-time truth but for our specific purpose, we do not need a hard realtime answer to this but can settle for a best guess. We would just like to, in theory, contact the current primary for the specific partition resolved by the ActorId and get back whether or not the device has an instantiated actor.
Ideally it is a fast/performant call, essentially faster than e.g. instantiating the actor and calling a method to understand if it has been initialized correctly and is not just an "empty" actor.
You can use the ActorServiceProxy to iterate through the information for a specific partition but that does not seem to be a very performant way of obtaining the information.
Anyone with insights into this?
The only official way you can check if the actor has been activated in any Service Partition previously is using the ActorServiceProxy query, like described here:
IActorService actorServiceProxy = ActorServiceProxy.Create(
new Uri("fabric:/MyApp/MyService"), partitionKey);
ContinuationToken continuationToken = null;
do
{
PagedResult<ActorInformation> page = await actorServiceProxy.GetActorsAsync(continuationToken, cancellationToken);
var actor = page.Items.FirstOrDefault(x => x.ActorId == idToFind);
continuationToken = page.ContinuationToken;
}
while (continuationToken != null);
By the nature of SF Actors, they are virtual, that means they always exist, even though you didn't activated then previously, so it make a bit harder to do this check.
As you said, it is not performant to query all actors, so, the other workarounds you could try is:
Store the IDs in a Reliable Dictionary elsewhere, every time an Actor is activated you raise an event and insert the ActorIDs in the Dictionary if not there yet.
You can use the OnActivateAsync() actor event to notify it's creation, or
You can use the custom actor factory in the ActorService to register actor activation
You can store the dictionary in another actor, or another StatefulService
Create a property in the actor that is set by the actor itself when it is activated.
The OnActivateAsync() check if this property has been set before
If not set yet, you set a new value and store in a variable (a non persisted value) to say the actor is new
Whenever you interact with actor you set this to indicate it is not new anymore
The next activation, the property will be already set, and nothing should happen.
Create a custom IActorStateProvider to do the same as mentioned in the option 2, instead of handle it in the actor it will handle a level underneath it. Honestly I think it is a bit of work, would only be handy if you have to do the same for many actor types, the option 1 and 2 would be much easier.
Do as Peter Bons Suggested, store the ActorID outside the ActorService, like in a DB, I would only suggest this option if you have to check this from outside the cluster.
.
The following snipped can help you if you want to manage these events outside the actor.
private static void Main()
{
try
{
ActorRuntime.RegisterActorAsync<NetCoreActorService>(
(context, actorType) => new ActorService(context, actorType,
new Func<ActorService, ActorId, ActorBase>((actorService, actorId) =>
{
RegisterActor(actorId);//The custom method to register the actor if new
return (ActorBase)Activator.CreateInstance(actorType.ImplementationType, actorService, actorId);
})
)).GetAwaiter().GetResult();
Thread.Sleep(Timeout.Infinite);
}
catch (Exception e)
{
ActorEventSource.Current.ActorHostInitializationFailed(e.ToString());
throw;
}
}
private static void RegisterActor(ActorId actorId)
{
//Here you will put the logic to register elsewhere the actor creation
}
Alternatively, you could create a stateful DeviceActorStatusActor which would be notified (called) by DeviceActor as soon as it's created. (Share the ActorId for correlation.)
Depending on your needs you can also register multiple Actors with the same status-tracking actor.
You'll have great performance and near real-time information.
Long description:
In our gwt with mvp4g app we have pretty complicated flow of events in eventbus. One event like LOGIN produces multiple others as a reaction from presenters/handlers. Currently we have great difficulties with understanding how events interrelated i.e. which events must follow this particular one.
We have tests for presenters and views, but we are lacking tests which would clearly show/model event flows, preferably without usage of real views and services.
Short description:
New tests on eventBus(?) should be developed which should clearly describe and test event flows.
I have few rud ideas but they all sounds not satisfactory:
Write custom implementation(could be ugly) of mvp4g eventbus and:
use real presenters
use mock(?) views
mock services
verify all produced service calls
Why not cool: (a) In this case test would not verify produced events directly but only that ones which have services. (b)
EventBus implementation would look rather scarry - it must create each presenter with mocked services and views
Find a way to use some magical mvp4g mechanism to create eventBus in test and mock vies, services.
Why not cool : same as prev - only indirect verification through services is possible, and I cannot find how to create eventBus manually and solve all problems with GIN, inter GWT module dependencies and so. I guess there is no simple way to do it.
Is there any general solution for problem of tracking event tree in tests? Guess I'm not the first person to stare at complicated eventbus event flows.
Do you want to test the eventBus? Or do you want to track all event which are fired?
If you want to track your events, maybe some kind of EventMonitor could help you? A class that implements all necessary EventHandler and log every event that occurs.
Something like that? Just instance that class before your tests starts.
import java.util.logging.Logger;
import com.google.gwt.event.shared.GwtEvent;
import com.google.web.bindery.event.shared.EventBus;
public class EventMonitor implements AEventHandler, BEventHandler /* , ... */{
private static int event_count = 1;
private final Logger logger = Logger.getLogger(this.getClass().getName());
public EventMonitor(EventBus eventBus) {
eventBus.addHandler(AEvent.getType(), this);
eventBus.addHandler(BEvent.getType(), this);
// [...]
}
private void logEvent(GwtEvent<?> event) {
logger.info(event_count + " useful information");
event_count++;
}
#Override
public void onAEvent(AEvent event) {
logEvent(event);
}
#Override
public void onBEvent(BEvent event) {
logEvent(event);
}
}
I implemented in Java what I called a "foldable queue", i.e., a LinkedBlockingQueue used by an ExecutorService. The idea is that each task as a unique id that if is in the queue while another task is submitted via that same id, it is not added to the queue. The Java code looks like this:
public final class FoldablePricingQueue extends LinkedBlockingQueue<Runnable> {
#Override
public boolean offer(final Runnable runnable) {
if (contains(runnable)) {
return true; // rejected, but true not to throw an exception
} else {
return super.offer(runnable);
}
}
}
Threads have to be pre-started but this is a minor detail. I have an Abstract class that implements Runnable that takes a unique id... this is the one passed in
I would like to implement the same logic using Scala and Akka (Actors).
I would need to have access to the mailbox, and I think I would need to override the ! method and check the mailbox for the event.. has anyone done this before?
This is exactly how the Akka mailbox works. The Akka mailbox can only exist once in the task-queue.
Look at:
https://github.com/jboner/akka/blob/master/akka-actor/src/main/scala/akka/dispatch/Dispatcher.scala#L143
https://github.com/jboner/akka/blob/master/akka-actor/src/main/scala/akka/dispatch/Dispatcher.scala#L198
Very cheaply implemented using an atomic boolean, so no need to traverse the queue.
Also, by the way, your Queue in Java is broken since it doesn't override put, add or offer(E, long, TimeUnit).
Maybe you could do that with two actors. A facade one and a worker one. Clients send jobs to facade. Facade forwards then to worker, and remember them in its internal state, a Set queuedJobs. When it receives a job that is queued, it just discard it. Each time the worker starts processing a job (or completes it, whichever suits you), it sends a StartingOn(job) message to facade, which removes it from queuedJobs.
The proposed design doesn't make sense. The closest thing to a Runnable would be an Actor. Sure, you can keep them in a list, and not add them if they are already there. Such lists are kept by routing actors, which can be created from ready parts provided by Akka, or from a basic actor using the forward method.
You can't look into another actor's mailbox, and overriding ! makes no sense. What you do is you send all your messages to a routing actor, and that routing actor forwards them to a proper destination.
Naturally, since it receives these messages, it can do any logic at that point.
Is there a way to cancel/abort request factory requests? Using GWT 2.3
There is no way to cancel a request after the fire() method has been called. Consider building a custom Receiver base class such as the following:
public abstract class CancelableReceiver<V> extends Receiver<V> {
private boolean canceled;
public void cancel() {
canceled = true;
}
#Override
public final void onSuccess(V response) {
if (!canceled) {
doOnSuccess(response);
}
}
protected abstract void doOnSuccess(V response);
}
The pattern can be repeated for other methods in the Receiver type.
Another option would be to create an alternative com.google.web.bindery.requestfactory.shared.RequestTransport type, instead of using DefaultRequestTransport. Downside to this (and upside to BobV's approach) is that you won't know when in the request on the server you kill it, so it might have already run some of your methods - you won't get feedback from any of them, you'll just stop the outgoing request.
I suspect this is why RF doesn't have this feature already, as RPC does. Consider even the case of RPC though or RequestBuilder - how do those notify the server that they've changed their mind, and to not run the request? My understanding is that they don't - the only way they are shut down early is when they try to read/write to the response, and get a tcp error, as the connection has been closed. (It's possible I am mistaken, and that another thread keeps an eye on the state of the tcp connection and calls thread.stop(Throwable), but stop has been deprecated for quite a while.)
One thought would be to send a message to the server, telling it to kill off other requests from the same session - this would require active participation in your server code though, possibly made generic in a ServiceLayerDecorator subtype, probably in at least invoke, loadDomainObject(s), and getSetter, among others. This pretty clearly is to involved to ask GWT to build it for you though...
Can you register EJB A as callback in an MDB B?
B.register(Aref)
in B: A.callback()
What would be Aref if the EJBs use local calls?
SessionContext.getEJBLocalObject()?
What you ask is not really possible in the proposed way.
If B is a Message Driven Bean, then it's never possible to call a method on it. In the messaging paradigm, the type of the receiver of a message is unknown. You thus can't reference an instance of the MDB. Instead, you post messages to a queue or topic and if your MDB is configured to listen to that its onMessage() method will be invoked.
Secondly, in EJB you don't often pass references around like in your example code. What kind of EJB bean is A supposed to be? A stateless session bean, or a stateful session bean?
In case it's a stateless session bean, the instance might not matter and you can probably just inject it:
#MessageDriven
public class NSMessageDrivenBean implements MessageListener {
#EJB
private A yourABean;
public void onMessage(Message message) {
// process message and then call A
yourABean.someMethod();
}
}
If the callback needs to be done to a type that is unknown in advance (depending on the message being send), then one mechanism for this is via a JMS reply.
In the message being send to the message driven bean, you then include code like this:
message.setJMSReplyTo(someDestination);
message.setJMSCorrelationID(someCorrelationID);
someDestination represents your callback, it's a destination to which something is listening, and this something can then invoke the call on the stateless session bean (in the context of the client).
E.g. something like:
connection.createSession(false, Session.AUTO_ACKNOWLEDGE).createConsumer(someDestination).setMessageListener(
new MessageListener() {
#Override
public void onMessage(Message message) {
yourABean.someMethod();
}
}
In this case, someDestination can be a temporary destination.