The Delphi-event-bus library (publish/subscribe Event Bus framework) by spinettaro deserves more popularity - it's thread-safe, it's simple yet flexible (I meant it), and supports async messaging. From what I know, I can say it's the only one of its kind that supports all the above mentioned features.

The Delphi-event-bus library (publish/subscribe Event Bus framework) by spinettaro deserves more popularity - it's thread-safe, it's simple yet flexible (I meant it), and supports async messaging. From what I know, I can say it's the only one of its kind that supports all the above mentioned features.
https://github.com/spinettaro/delphi-event-bus

Comments

  1. I prefer p2p RDP to a bus pattern. Our SOA is based on interfaces and allow asynchronous notifications using websockets. Messages are defined as interface methods, which is very convenient. It works locally with direct immediate calls, or may work remotely if needed. If you need a bus, or a publish/subscribe pattern, it is very easy to setup it from interfaces. See http://stackoverflow.com/a/29470232

    ReplyDelete
  2. Edwin Yip Did you have a close look at the code? Some parts are just "thread-safe look-alike"

    As an example: https://github.com/spinettaro/delphi-event-bus/blob/master/source/EventBus.pas#L87

    ReplyDelete
  3. Oliver Münzberg Oh wow, that's bad. Hard to trust the rest...

    ReplyDelete
  4. Oliver Münzberg That is a showstopper. FWIW how to initialize singleton in a thread-safe way (see starting from line 100): https://bitbucket.org/sergworks/tforge/src/1ebd4d756894e26e5153761586833afdaad9e59d/Source/Engine/OSes/tfWindows.pas

    ReplyDelete
  5. It's unclear to me why the singleton instance is even needed. All the variables are class vars - the instance methods could just be made class methods similarly, including the constructor and destructor. Do things that way and the GetDefault method can be removed completely.

    ReplyDelete
  6. A. Bouchez If the lock is needed only internal I use TMonitor.Lock that is the fastest way to lock ... but if the source targets a wide range of delphi versions (as your lib does) then I would also avoid using TMonitor (there was a bug in the implementation which was fixed in version ???)

    ReplyDelete
  7. A. Bouchez Actually I know that part of mORMot, my concern is that, assume I have 100 event types (This amount can be easily reached since my intention is to use the event bus for de-coupling various parts of the program). With your implementation, I will *either* have to define an interface with 100 methods and implement all these methods in all classes those need to receive events, *or* in the client define a single, centralized method to re-dispatch the events. Either way is clean and simple. Plz correct me if I'm wrong. on the other hand, with delphi-event-bus, the client only need to define the type of event it's interested and the method to receive it, like this:
    [code]
    [Subscribe]
    procedure OnMemoChange(AEvent: TMemoChangeEvent);
    [/code]

    ReplyDelete
  8. Oliver Münzberg I actually only compiled it and checked the vcl messaging sample. Either way, it has a great concept and simple implementation, such potential issues can be fixed, after all. And this is exactly how an open source project progress: - A new, useful project emerged, get attention by the community and get discussed like this conversation, things get enhanced and benefit the community. Nothing is perfect, especially when its new, but no doubt this library can be very useful - its concept enables modules to communicate without knowing each other, in a *simple* way. Check this for this concept: http://www.slideshare.net/nzakas/scalable-javascript-application-architecture/15-How_does_this_apply_to

    ReplyDelete
  9. Edwin Yip I do not argue against the concept (that I like very much) but the implementation is very odd.

    ReplyDelete
  10. Oliver Münzberg  I know. Very useful input :)

    ReplyDelete
  11. Since it's a github project, you can file bugs or fix the threading issue and make a pull request. (I think it's trying to implement double-checked locking, but as others have said it's not the right way to do it.)

    ReplyDelete
  12. Edwin Yip Just follow the "interface segregation" SOLID principle, and define as much interfaces are there are bounded context in your system. Then use a dedicated set of publish/subscribe methods, one per interface, for the clients.
    But I guess that if you have a lot of messages, it smells like if you are mixing layers (in terms of DDD), so perhaps you may even not only uncouple your interfaces horizontally (i.e. at the same level), but also vertically (i.e. at another layer). For instance, persistence services should be in the infrastructure layer, and not mix with business (domain) services, or application level controllers.
    This is why I like so much DDD principles. I use mORMot in some huge projects todays, with a growing number of services, and uncoupling following DDD is mandatory for maintainability, and even performance.

    ReplyDelete
  13. Oliver Münzberg Indeed. TMonitor never convinced me: it is (was?) slow - ask Eric Grange blog articles (why not just use the OS APIs?), and it is clearly a Java anti-pattern introduced to Delphi.
    Poor TObject, which has been polluted by this TMonitor stuff, without asking anything!
    What if you want to lock several objects, or just some members of your object? IMHO explicit and clearly named locks are a much cleaner alternative.
    You usually don't lock an object. You lock a part of the process, trying to have as many small locks as possible, to reduce contention and potential race conditions.

    ReplyDelete
  14. A. Bouchez TMonitor is fast and fine in newer Delphi versions - and performance was not the issue but the misbehaviour in some cases.

    It does not matter what your lock is based on (TMonitor, Event, Mutex, CriticalSection,...) but locking with TMonitor on self is wrong in almost every situation and can lead to a deadlock.

    ReplyDelete
  15. A. Bouchez Thanks for the comment, but actually I'm planning to use the Event Bus for thread-safe, no-window-handles message broadcasting for *UI-related* actions, so I think it's a different story. Quoting from (http://greenrobot.org/eventbus): "EventBus is an open-source library for Android using the publisher/subscriber pattern to solve the problem of loose coupling. EventBus enables central communication to decoupled classes with just a few lines of code – simplifying the code, removing dependencies, and speeding up app development."

    ReplyDelete
  16. Oliver Münzberg  given the stability issues with TMonitor, and various thread-safe issues that affect the RTL, I would still not trust it, thread-safety is very hard to test, and in the end, it is still just NIHS. The OSes provide all the necessary thread-safety mechanisms, which are heavily tested, and they will appropriately scale or be updated to scale to various hardware you are running on (while TMonitor obviously won't).

    Edwin Yip for a UI, a message queue can be simpler to debug, because the FIFO nature of a queue makes the sequence of events predictable. A good and efficient bus on the other hand will reorder events, because the purpose of a bus is to deliver messages fast, asap and reliably, not deliver them in order (otherwise, by definition it's not a bus, it's a queue).

    So for instance if a bus delivers a keyup before a keydown, it would not be a bug, while it would be for a queue.

    When your UI is handling messages fast enough, that will not happen because there is some physical delay, but if your UI is getting stuck for a bit of time, this could happen. And by "getting stuck", you have to think "taking more than a few milliseconds to process the event" as milliseconds is the delay you can encounter for keypress, mouse move or touch events.

    And this could also happen in more subtle ways: if your UI is really decoupled, multi-thread and asynchronous, if user clicks on button1 then button2, but button1 processing takes more time than the time between both clicks, with a bus, button2 could get the message before button1, while with a queue it could not (but the whole UI would appear stuck instead).

    The upside of a bus is that a slow message processing won't stall other messages, the downside is that your UI has to guard against that, which can complicate the code quite a bit, and can lead to bugs that are very hard to reproduce.

    ReplyDelete
  17. Eric Grange Yes, using TMonitor is somehow religion "Did I trust Emba that they implement it properly". But using the OSes function is nearly the same religion (but tested/proven by a much wider range of developers). When building very high critical applications I would always tend to use the OSes functions ;o)

    ReplyDelete
  18. Hi everybody! First of all, thanks to Edwin Yip who have mentioned my project. I fixed the Critical Section mistake ( the code was not clear also for me, maybe I haven't to write code in late night :) ). As Edwin wrote in previous post, this is an open source project (a benefit for the community), so if you think that might be a potential in this project I'm glad to discuss with you about fixes, enhancements, new features etc...

    ReplyDelete

Post a Comment