I have got multiple instances of a class which listen to a certain event.
#Inject
#Optional
private final void doSomething(#UIEventTopic(Events.A) Object object) {
//do something
}
My question is: if I use the synchronous method IEventBroker.send, will this method reliably wait until all of the listening objects are done? My tests indicate yes, but I would just like to make sure.
The JavaDoc for IEventBroker.send says:
Publish event synchronously (the method does not return until the
event is processed).
Internally the event broker uses the OSGi EventAdmin.sendEvent method, which says:
Initiate synchronous delivery of an event. This method does not return
to the caller until delivery of the event is completed.
So, Yes synchronous delivery is guaranteed.
Related
In my API I have a POST request which alters data.
The underlying code looks something like this:
#RestController
#RequiredArgsConstructor
public class FooControllerImpl implements FooController {
private final FooService fooService;
#PostMapping("api/foo/{fooId}")
public FooRsDto alterFoo(#RequestBody FooRqDto body, #PathVariable fooId) {
return fooService.alterFoo(body, fooId);
}
}
Inside fooService.alterFoo(...) I want to publish an event which will be processed inside an implementation of EventListener which in turn will publish data to a websocket channel.
But from the javadoc it follows that a simple implementation of EventListener will be synchronous. Does that mean that:
It will be synchronous within a thread where a request is processed?
It will be synchronous within the whole application? (meaning I won't be able to publish from listener to a websocket to different users, so I'll have to resort to making an async listener?)
Upd:
Ok, it seems that I've found the answer. Accorindg to the javadoc for SimpleApplicationEventMulticaster where it's stated that:
By default, all listeners are invoked in the calling thread.
So, not using async seems ok in this particular use case.
Does anyone know how to write a custom Event Dispatcher based on the javafx.event package? I searched in Google & Co. but didn't find a nice example.
Have anyone a minimalistic example for me? That would be nice - I tried it a few times to understand it, but I failed.
The first thing to realize is how JavaFX dispatches events.
When an Event is fired it has an associated EventTarget. If the target was in the scene-graph then the path of the Event starts at the Window and goes down the scene-graph until the EventTarget is reached. The Event then goes back up the scene-graph until it reaches the Window again. This is known as the "capturing phase" and the "bubbling phase", respectively. Event filters are invoked during the capturing phase and event handlers are invoked during the bubbling phase. The EventHandlers set using the onXXX properties (e.g. onMouseClicked) are special types of handlers (i.e. not filters).
The EventDispatcher interface has the following method:
public Event dispatchEvent(Event event, EventDispatChain tail) { ... }
Here, the event is the Event being dispatched and the tail is the EventDispatchChain built, possibly recursively, by EventTarget.buildEventDispatchChain(EventDispatchChain). This will return null if the event is consumed during execution of the method.
The EventDispatchChain is a stack of EventDispatchers. Every time you call tail.dispatchEvent(event) you are essentially popping an EventDispatcher off the top and invoking it.
#Override
public Event dispatchEvent(Event event, EventDispatchChain tail) {
// First, dispatch event for the capturing phase
event = dispatchCapturingEvent(event);
if (event.isConsumed()) {
// One of the EventHandlers invoked in dispatchCapturingEvent
// consumed the event. Return null to indicate processing is complete
return null;
}
// Forward the event to the next EventDispatcher in the chain
// (i.e. on the stack). This will start the "capturing" on the
// next EventDispatcher. Returns null if event was consumed down
// the chain
event = tail.dispatchEvent(event);
// once we've reached this point the capturing phase has completed
if (event != null) {
// Not consumed from down the chain so we now handle the
// bubbling phase of the process
event = dispatchBubblingEvent(event);
if (event.isConsumed()) {
// One of the EventHandlers invoked in dispatchBubblingEvent
// consumed the event. Return null to indicate processing is complete
return null;
}
}
// return the event, or null if tail.dispatchEvent returned null
return event;
}
You're probably wondering where dispatchCapturingEvent and dispatchBubblingEvent are defined. These methods would be created by you and would invoke the appropriate EventHandlers. You might also be wondering why these methods return an Event. The reason is simple: During the processing of the Event these methods, along with tail.dispatchEvent, might alter the Event. Other than consume(), however, Event and its subclasses are basically immutable. This means any other alterations require the creation of a new Event. It is this new Event that should be used by the rest of the event-handling process.
The call to tail.dispatchEvent will virtually always return a new instance of the Event. This is due to the fact each EventDispatcher in the EventDispatchChain is normally associated with its own source (e.g. a Label or Window). When an EventHandler is being invoked the source of the Event must be the same Object that the EventHandler was registered to; if an EventHandler was registered with a Window then event.getSource() must return that Window during said EventHandler's execution. The way this is achieved is by using the Event.copyFor(Object,EventTarget) method.
Event oldEvent = ...;
Event newEvent = oldEvent.copyFor(newSource, oldEvent.getTarget());
As you can see, the EventTarget normally remains the same throughout. Also, subclasses may override copyFor while others, such as MouseEvent, may also define an overload.
How are the events actually dispatched to the EventHandlers though? Well, the internal implementation of EventDispatcher makes them a sort of "collection" of EventHandlers. Each EventDispatcher tracks all filters, handlers, and property-handlers (onXXX) that have been added to or removed from its associated source (e.g. Node). Your EventDispatcher doesn't have to do this but it will need a way to access wherever you do store the EventHandlers.
During the capturing phase the EventDispatcher invokes all the appropriate EventHandlers added via addEventFilter(EventType,EventHandler). Then, during the bubbling phase, the EventDispatcher invokes all the appropriate EventHandlers added via addEventHandler(EventType,EventHandler) or setOnXXX (e.g. setOnMouseClicked).
What do I mean by appropriate?
Every fired Event has an associated EventType. Said EventType may have a super EventType. For instance, the "inheritance" tree of MouseEvent.MOUSE_ENTERED is:
Event.ANY
InputEvent.ANY
MouseEvent.ANY
MouseEvent.MOUSE_ENTERED_TARGET
MouseEvent.MOUSE_ENTERED
When dispatching an Event you have to invoke all the EventHandlers registered for the Event's EventType and all the EventType's supertypes. Also, note that consuming an Event does not stop processing of that Event for the current phase of the current EventDispatcher but instead finishes invoking all appropriate EventHandlers. Once that phase for that EventDispatcher has completed, however, the processing of the Event stops.
Whatever mechanism you use to store the EventHandlers must be capable of concurrent modification by the same thread. This is because an EventHandler may add or remove another EventHandler to or from the same source for the same EventType for the same phase. If you stored them in a regular List this means the List may be modified while you're iterating it. A readily available example of an EventHandler that may remove itself is WeakEventHandler. A WeakEventHandler will attempt to remove itself if it is invoked after it has been "garbage collected".
Also, I don't know if this is required, but the internal implementation doesn't allow the same EventHandler to be registered more than once for the same source, EventType, and phase. Remember, though, that the EventHandlers added via addEventHandler and those added via setOnXXX are handled separately even though they are both invoked during the same phase (bubbling). Also, calling setOnXXX replaces any previous EventHandler set for the same property.
What is the best practice for handling exceptions in MassTransit 3+ with regard to Request/Response pattern? The docs here mention that if a ResponseAddress exists on a message, the Fault message will be sent to that address, but how does one consumer/receive the messages at that address? The ResponseAddress for Bus.Request seems to be an auto-generated MassTransit address that I don't have control over, so I don't know how to access the exception thrown in the main consumer. What am I missing? Here's my code to register the consumer and its fault consumer using Unity container:
cfg.ReceiveEndpoint(host, "request_response_queue", e =>
{
e.Consumer<IConsumer<IRequestResponse>>(container);
e.Consumer(() => container.Resolve<IMessageFaultConsumer<IRequestResponse>>() as IConsumer<Fault<IRequestResponse>>);
});
And here's my attempt at a global message fault consumer:
public interface IMessageFaultConsumer<TMessage>
{
}
public class MessageFaultConsumer<TMessage> : IConsumer<Fault<TMessage>>, IMessageFaultConsumer<TMessage>
{
public Task Consume(ConsumeContext<Fault<TMessage>> context)
{
Console.WriteLine("MessageFaultConsumer");
return Task.FromResult(0);
}
}
This approach DOES work when I use Bus.Publish as opposed to Bus.Request. I also looked into creating an IConsumeObserver and putting my global exception logging code into the ConsumeFault method, but that has the downside of being invoked every exception prior to the re-tries giving up. What is the proper way to handle exceptions for request/response?
First of all, the request/response support in MassTransit is meant to be used with the .Request() method, or the request client (MessageRequestClient or PublishRequestClient). With these methods, if the consumer of the request message throws an exception, that exception is packaged into the Fault<T>, which is sent to the ResponseAddress. Since the .Request() method, and the request client are both asynchronous, using await will throw an exception with the exception data from the fault included. That's how it is designed, await the request and it will either complete, timeout, or fault (throw an exception upon await).
If you are trying to put in some global "exception handler" code for logging purposes, you really should log those at the service boundary, and an observer is the best way to handle it. This way, you can just implement the ConsumeFault method, and log to your event sink. However, this is synchronous within the consumer pipeline, so recognize the delay that could be introduced.
The other option is to of course just consume Fault<T>, but as you mentioned, it does not get published when the request client is used with the response address in the header. In this case, perhaps your requester should publish an event indicating that operation X faulted, and you can log that -- at the business context level versus the service level.
There are many options here, it's just choosing the one that fits your use case best.
I have extended EventNotiferSupport, and set the isEnable() to respond True for all events. I have a notify() that logs what events I receive and the corresponding Exchange ID for the event.
I have added my ExchangeMessageNotifier with this.context.getManagementStrategy().addEventNotifier(this.exchangeMessageNotifier);
I run my program under basically no load, sending 1 message at a time 1 second delay between messages into Camel to send out. Everything works the way I expect. I receive my events everything looks good.
I decrease the delay between messages to 0 milliseconds, and I find that 1 out of approximately 20 messages I fail to receive one of the Events, (Often the Completed event).
Add a second thread sending at the same rate and I don't get any events for any messages.
What am I missing? I've done searches and I don't find anything that I need to do differently. Is there something I am missing?
I am using Apache Camel 2.16.3, and moved to 2.18.1 still see the same behavior.
Well found my own answer. Part of the fun of inheriting code without any informaiton.
In your implementation of the EventNotifierSupport you need to override the doStart() method and configure the EventNotifierSupport for what events you wish to receive.
protected void doStart() throws Exception {
// filter out unwanted events
setIgnoreCamelContextEvents(true);
setIgnoreServiceEvents(true);
setIgnoreRouteEvents(true);
setIgnoreExchangeCreatedEvent(true);
setIgnoreExchangeCompletedEvent(false);
setIgnoreExchangeFailedEvents(true);
setIgnoreExchangeRedeliveryEvents(true);
setIgnoreExchangeSentEvents(false);
}
This is in addition to doing the following:
public boolean isEnabled(EventObject event) {
return true;
}
Which enables you to determine if you want a particular event, out of the selected groups you had set in the doStart().
Once these changes were in I was receiving consistent events.
If I have a class that listens to event emitters, is it wrong practice to bind on every instance?
function MyClass() {
emitter.on('ready', function() {
// do something
});
}
myclass = new MyClass();
If I call emitter.on() multiple times, it warns me.
(node) warning: possible EventEmitter memory leak detected. 11
listeners added. Use emitter.setMaxListeners() to increase limit.
Are event emitters meant to be bound only once per module, outside of class instances?
If this is wrong, then how do I access the class instance when events are triggered?
Thanks
The warning is that your attaching 11 event listeneres to the ready event on a single event emitter.
Generally when you listen to the same event multiple times on a single event emitter, it's likely that's a bug. For example say you have an http event emitter, if your listening on the request event 11 times that's probably a bug, you only want to listen and handle request once.
This is a debugging tool. You can get around this by doing
emitter.setMaxListeners(500); // or whatever you think is a sensible limit