Jump to content
Javier Tarí

Delphi Event Bus vs NX Horizon

Recommended Posts

After finishing migration from D2007 I could finally use libraries that previously were not available to me

Now I needed to add an Event Bus implementation to my toolbox, and was between Delphi Event Bus and NX Horizon

So I asked Claude Code to make me a summary of each one, and also an argumented list of strengths and weaknesses

Then I asked it to assess me for my use case (I'm an ERP developer)

 

spinettaro/delphi-event-bus: Delphi Event Bus (for short DEB) is an Event Bus framework for Delphi

dalijap/nx-horizon: NX Horizon - Event Bus for Delphi

 

● Event Bus Comparison & Recommendation for CyberMAX ERP

  After analyzing both implementations, here's my detailed comparison and recommendation:

  Architecture Comparison

  | Aspect       | Delphi Event Bus (DEB)                     | NX Horizon                                 |
  |--------------|--------------------------------------------|--------------------------------------------|
  | Code Size    | 1,790 lines (4 files)                      | 715 lines (1 file)                         |
  | Event Types  | Dual: Interface-typed + Named channels     | Single: Type-based (TypeInfo)              |
  | Thread Modes | 4 modes (Posting, Main, Async, Background) | 4 modes (Sync, Async, MainSync, MainAsync) |
  | Subscription | Attribute-based ([Subscribe], [Channel])   | Programmatic with interface return         |
  | Min Version  | Delphi 2010                                | Delphi XE4                                 |
  | Thread Pool  | Custom (Delphi 28.0+), fallback to TThread | TTask (XE7+), fallback to TThread          |

  Critical Differences for ERP

  1. Memory Management

  - DEB: Potential memory leaks with circular references, no automatic cleanup
  - NX Horizon: Better reference counting with INxEvent wrapper, explicit ownership model

  2. Error Handling

  - DEB: Silent failures, no exception isolation, can stop delivery chain
  - NX Horizon: Also has silent async failures but better structured for adding error handling

  3. Thread Safety

  - DEB: Global lock bottleneck, potential race conditions in cache
  - NX Horizon: Superior thread safety with countdown events and proper cleanup

  4. API Design

  - DEB: More complex with dual event types but richer features
  - NX Horizon: Simpler, cleaner API with single paradigm

  Strengths for ERP Integration

  Delphi Event Bus:
  - Named channels perfect for module communication (TCConta ↔ Almacen)
  - Attribute-based subscriptions match your DataModule patterns
  - Context strings useful for client-specific routing (AIR, GAN, GMC)
  - Global singleton aligns with your dmModule pattern

  NX Horizon:
  - Better memory safety critical for 24/7 ERP operation
  - WaitFor mechanism ensures clean module shutdown
  - Simpler codebase easier to maintain and debug
  - Superior thread safety for concurrent user operations

  Weaknesses for ERP

  Delphi Event Bus:
  - Memory leak risks in long-running ERP sessions
  - No automatic cleanup could cause crashes with dynamic module loading
  - Silent failures problematic for critical business operations
  - Global lock could bottleneck multi-user scenarios

  NX Horizon:
  - No named channels means more boilerplate for module communication
  - Requires explicit type declarations for each event
  - Less feature-rich for complex routing scenarios
  - No attribute-based configuration

  🎯 Recommendation: NX Horizon

  For CyberMAX ERP integration, I recommend NX Horizon for these reasons:

  1. Reliability: Superior memory management and thread safety are critical for an ERP that runs continuously and
  handles financial data.
  2. Maintainability: Single-file implementation (715 lines) is easier to understand, debug, and modify than DEB's
  4-file architecture.
  3. Safety: The WaitFor pattern aligns perfectly with your DataModule lifecycle, ensuring clean shutdown of
  interdependent modules.
  4. Performance: No global lock bottleneck means better scalability for multiple concurrent users.
  5. Integration Path: The type-based approach maps well to your existing record types (dmodModule.records.pas).

  Integration Strategy  // Define events for module communication

  type
    TFacturaCreatedEvent = INxEvent<TFacturaRecord>;
    TStockUpdateEvent = INxEvent<TAlmacenMovimiento>;
    TContaAsientoEvent = type Integer; // AsientoID

  // In your DataModule hierarchy
  TdmModuleHigh = class(TdmModule)
  private
    fEventSubscriptions: TList<INxEventSubscription>;
  public
    procedure AfterConstruction; override;
    procedure BeforeDestruction; override;
  end;

  Migration Considerations

  If you need channel-like behavior, create a wrapper:
  type
    TChannelEvent = record
      Channel: string;
      Data: TValue;
    end;
    TChannelMessage = INxEvent<TChannelEvent>;

 

Edited by Javier Tarí
adding links to the repositories

Share this post


Link to post

> Explain me how this impact use and use cases:
    - No named channels means more boilerplate for module communication
    - Requires explicit type declarations for each event
    - Less feature-rich for complex routing scenarios
    - No attribute-based configuration

● Let me explain the practical impact of these NX Horizon limitations for your ERP development:

  1. No Named Channels = More Boilerplate  DEB (with channels):

  // Simple string-based messaging
  GlobalEventBus.Post('INVOICE_CREATED', '{"id": 1234}');

  // Any module can listen
  [Channel('INVOICE_CREATED')]
  procedure OnInvoiceMessage(AMsg: string);

  NX Horizon (without channels):

  // Must define a type for EVERY communication
  type
    TInvoiceCreatedEvent = record
      InvoiceID: Integer;
      CustomerID: Integer;
      Total: Currency;
    end;

  // Post requires creating the record
  var Event: TInvoiceCreatedEvent;
  begin
    Event.InvoiceID := 1234;
    Event.CustomerID := 5678;
    Event.Total := 1500.50;
    NxHorizon.Instance.Post(Event);
  end;

  Impact: For quick module-to-module notifications, you'll write 5-10 lines instead of 1.

  2. Explicit Type Declarations Required  Problem in practice:

  // Want to notify about 20 different business events?
  // Need 20 type declarations:
  type
    TFacturaCreatedEvent = type Integer;
    TFacturaModifiedEvent = type Integer;
    TFacturaCanceledEvent = type Integer;
    TAlbaranCreatedEvent = type Integer;
    TPedidoCreatedEvent = type Integer;
    TClienteUpdatedEvent = record
      ClienteID: Integer;
      ChangeType: string;
    end;
    // ... 14 more types

  Impact: Your codebase gets cluttered with event type definitions. In DEB, you'd just use different channel names.

  3. Less Feature-Rich for Complex Routing  DEB's context-based routing:

  // Post to specific client modules only
  GlobalEventBus.Post(MyEvent, 'Context:AIR');  // Only AIR module receives
  GlobalEventBus.Post(MyEvent, 'Context:GAN');  // Only GAN module receives

  // Subscribe with context filtering
  [Subscribe(TThreadMode.Main, 'Context:AIR')]
  procedure OnAirSpecificEvent(AEvent: IMyEvent);

  NX Horizon - no built-in filtering:
  // ALL subscribers get ALL events of that type

  procedure OnInvoiceCreated(const AEvent: TInvoiceCreatedEvent);
  begin
    // Must filter manually
    if not IsMyClient(AEvent.ClientCode) then
      Exit;  // Wasted call

    // Process event
  end;

  Impact:
  - Can't route events to specific modules without manual filtering
  - Performance hit from unnecessary handler calls
  - More complex code in handlers

  4. No Attribute-Based Configuration  DEB's declarative style:

  TMyDataModule = class
    [Subscribe(TThreadMode.Background)]
    procedure OnSlowProcess(AEvent: ISlowEvent);  // Automatically background

    [Subscribe(TThreadMode.Main)]
    procedure OnUIUpdate(AEvent: IUIEvent);  // Automatically main thread

    [Channel('ALERTS', TThreadMode.Main)]
    procedure OnAlert(AMsg: string);  // Channel + thread mode
  end;

  NX Horizon's programmatic style:

  TMyDataModule = class
  private
    fSubSlowProcess: INxEventSubscription;
    fSubUIUpdate: INxEventSubscription;
    fSubAlert: INxEventSubscription;
  public
    constructor Create;
    begin
      // Must manually subscribe and track each subscription
      fSubSlowProcess := NxHorizon.Instance.Subscribe<TSlowEvent>(
        OnSlowProcess, TNxHorizonDelivery.Async);

      fSubUIUpdate := NxHorizon.Instance.Subscribe<TUIEvent>(
        OnUIUpdate, TNxHorizonDelivery.MainAsync);

      // No channel support - must create wrapper type
      fSubAlert := NxHorizon.Instance.Subscribe<TAlertEvent>(
        OnAlert, TNxHorizonDelivery.MainAsync);
    end;

    destructor Destroy;
    begin
      // Must manually clean up each subscription
      fSubSlowProcess.WaitFor;
      fSubUIUpdate.WaitFor;
      fSubAlert.WaitFor;
      // ...
    end;
  end;

  Impact:
  - More verbose code
  - Must manage subscription lifetime manually
  - Easy to forget cleanup → memory leaks

  Real-World ERP Scenario

  Imagine implementing "When invoice is created, update stock, create accounting entry, and notify UI":  With DEB:

  // Just post to channels
  GlobalEventBus.Post('INVOICE_CREATED', IntToStr(InvoiceID));
  GlobalEventBus.Post('STOCK_UPDATE', StockJSON);
  GlobalEventBus.Post('CONTA_ENTRY', ContaJSON);

  // Modules subscribe declaratively
  [Channel('INVOICE_CREATED')]
  procedure HandleInvoice(AMsg: string);

  With NX Horizon:

  // Define all event types first
  type
    TInvoiceCreatedEvent = type Integer;
    TStockUpdateEvent = record
      Items: TArray<TStockItem>;
    end;
    TContaEntryEvent = record
      AccountID: Integer;
      Amount: Currency;
    end;

  // More complex posting
  var
    InvEv: TInvoiceCreatedEvent;
    StockEv: TStockUpdateEvent;
    ContaEv: TContaEntryEvent;
  begin
    InvEv := InvoiceID;
    StockEv.Items := GetStockItems;
    ContaEv.AccountID := GetAccount;
    ContaEv.Amount := GetAmount;

    NxHorizon.Instance.Post(InvEv);
    NxHorizon.Instance.Post(StockEv);
    NxHorizon.Instance.Post(ContaEv);
  end;

  However, These Limitations Are Manageable

  The extra boilerplate provides benefits:
  - Type safety prevents runtime errors
  - Explicit contracts make code self-documenting
  - Compiler catches breaking changes
  - Better IDE support with code completion

  For a mission-critical ERP, these trade-offs are worth it for the superior reliability and thread safety that NX
  Horizon provides.

Share this post


Link to post

> If I have a group of related units, where one is the UI and the other provide business rules, tools, and logic, and
  I want to devouple the UI from the other units, would an event bus be a good solution? if it is a good solution,
  which one would be a better choice, DEB or NX?

● Yes, Event Bus is EXCELLENT for UI-Business Logic Decoupling

  This is actually one of the best use cases for an event bus pattern. Let me explain why and which one fits better.

  Why Event Bus Works Here  Traditional Coupled Approach:

  // UI knows about business logic directly
  uses
    BusinessRules, Tools, DataAccess, Calculations;

  procedure TfrmInvoice.btnCalculateClick(Sender: TObject);
  begin
    // UI directly calls business logic
    Total := TInvoiceCalculator.Calculate(Items);
    TInvoiceValidator.Validate(Invoice);
    TDataAccess.SaveInvoice(Invoice);
    TReportGenerator.Generate(Invoice);
  end;

  Decoupled with Event Bus:

  // UI only knows about events
  uses
    EventBus; // or NX.Horizon

  procedure TfrmInvoice.btnCalculateClick(Sender: TObject);
  begin
    // UI just publishes what happened
    EventBus.Post(TCalculateInvoiceCommand.Create(InvoiceID));
    // Business logic handles it somewhere else
  end;

  procedure TfrmInvoice.OnInvoiceCalculated(const Result: TInvoiceCalculatedEvent);
  begin
    // UI updates when business logic responds
    edtTotal.Text := FormatCurr('0.00', Result.Total);
    ShowValidationResults(Result.ValidationMessages);
  end;

  Benefits for Your Scenario

  1. UI can be replaced without touching business logic
  2. Business rules can change without recompiling UI
  3. Testing becomes easier - test business logic without UI
  4. Multiple UIs possible - VCL, FMX, Web, CLI can all use same business layer

  For UI Decoupling: DEB is the Better Choice

  Here's why DEB wins for this specific scenario:

  1. Attribute-Based Declaration is Cleaner for UI  DEB Approach:

  TfrmInvoice = class(TForm)
    // Declarative - immediately visible what events this form handles
    [Subscribe(TThreadMode.Main)]
    procedure OnInvoiceLoaded(AEvent: IInvoiceLoadedEvent);

    [Subscribe(TThreadMode.Main)]
    procedure OnCalculationComplete(AEvent: ICalculationCompleteEvent);

    [Subscribe(TThreadMode.Main)]
    procedure OnValidationFailed(AEvent: IValidationFailedEvent);

    [Channel('USER_NOTIFICATIONS')]
    procedure OnUserMessage(AMsg: string);
  end;

  NX Horizon Approach:

  TfrmInvoice = class(TForm)
  private
    FSub1, FSub2, FSub3, FSub4: INxEventSubscription;

    procedure SetupSubscriptions;
    begin
      // Hidden in implementation - harder to see what form responds to
      FSub1 := NxHorizon.Instance.Subscribe<TInvoiceLoadedEvent>(
        OnInvoiceLoaded, TNxHorizonDelivery.MainSync);
      FSub2 := NxHorizon.Instance.Subscribe<TCalculationCompleteEvent>(
        OnCalculationComplete, TNxHorizonDelivery.MainSync);
      // ... more setup code
    end;
  end;

  2. Context-Based Routing Perfect for Multiple Forms

  // DEB can route to specific forms/modules
  GlobalEventBus.Post(Event, 'Context:InvoiceForm');
  GlobalEventBus.Post(Event, 'Context:ReportForm');

  // Different forms subscribe to same event with different contexts
  [Subscribe(TThreadMode.Main, 'Context:InvoiceForm')]
  procedure OnUpdate(AEvent: IDataEvent);

  [Subscribe(TThreadMode.Main, 'Context:ReportForm')]
  procedure OnUpdate(AEvent: IDataEvent);

  3. Channel Pattern Natural for UI Events

  // Business logic sends UI notifications via channels
  GlobalEventBus.Post('SHOW_PROGRESS', '50');
  GlobalEventBus.Post('SHOW_ERROR', 'Invalid customer data');
  GlobalEventBus.Post('ENABLE_BUTTON', 'btnSave');

  // UI subscribes to channels
  [Channel('SHOW_PROGRESS')]
  procedure UpdateProgress(APercent: string);

  [Channel('SHOW_ERROR')]
  procedure ShowError(AMessage: string);

  4. Automatic Thread Marshaling to Main Thread  DEB's TThreadMode.Main is perfect for UI:

  // Business logic runs in background
  TTask.Run(procedure
  begin
    // Complex calculation in background thread
    Result := ComplexCalculation;

    // Post event - UI receives it on main thread automatically
    GlobalEventBus.Post(TCalculationDoneEvent.Create(Result));
  end);

  // UI method - always called on main thread
  [Subscribe(TThreadMode.Main)]
  procedure TfrmMain.OnCalculationDone(AEvent: ICalculationDoneEvent);
  begin
    // Safe to update UI controls directly
    lblResult.Caption := AEvent.Result;
  end;

  Practical Architecture Pattern

  // Events.pas - Shared between UI and Business
  type
    // Commands (UI → Business)
    ICalculateInvoiceCommand = interface
      function GetInvoiceID: Integer;
    end;

    // Events (Business → UI)
    IInvoiceCalculatedEvent = interface
      function GetTotal: Currency;
      function GetTaxes: Currency;
    end;

  // InvoiceForm.pas - UI Layer
  type
    TfrmInvoice = class(TForm)
      [Subscribe(TThreadMode.Main)]
      procedure OnInvoiceCalculated(AEvent: IInvoiceCalculatedEvent);

      procedure btnCalculateClick(Sender: TObject);
      begin
        GlobalEventBus.Post(TCalculateInvoiceCommand.Create(FInvoiceID));
      end;
    end;

  // InvoiceBusinessLogic.pas - Business Layer
  type
    TInvoiceService = class
      [Subscribe(TThreadMode.Background)]
      procedure OnCalculateCommand(ACmd: ICalculateInvoiceCommand);
      begin
        // Do calculation
        Result := Calculate(ACmd.GetInvoiceID);
        // Send result back to UI
        GlobalEventBus.Post(TInvoiceCalculatedEvent.Create(Result));
      end;
    end;

  Why Not NX Horizon for UI Decoupling?

  While NX Horizon is more reliable overall, for UI decoupling specifically:

  1. Too much boilerplate for the many events between UI and business
  2. No channels means you can't easily broadcast UI notifications
  3. Manual subscription management is tedious with many form events
  4. No context routing makes multi-form scenarios harder

  Recommendation

  Use DEB for UI-Business decoupling because:
  - Cleaner, more maintainable UI code
  - Natural fit for form-to-service communication
  - Channels perfect for notifications/alerts
  - Automatic main thread marshaling
  - Less boilerplate for many UI events  BUT consider wrapping it to mitigate weaknesses:

  type
    TUIEventBus = class
    private
      class var FInstance: IEventBus;
    public
      class procedure Post(AEvent: IInterface);
      class procedure Subscribe(AObject: TObject);
      class procedure Unsubscribe(AObject: TObject);
    end;

  This gives you an abstraction layer to switch implementations later if needed.

Share this post


Link to post

> and which one would give better results for coding with an AI agent? why?

● For AI Agent Coding: NX Horizon is SIGNIFICANTLY Better

  This is a crucial consideration that changes the recommendation. Here's why:

  1. Single File = Perfect AI Context

  NX Horizon:
  # AI gets everything in one read
  Read: NX.Horizon.pas  # 715 lines - COMPLETE implementation

  DEB:
  # AI must read 4 files to understand
  Read: EventBus.pas         # 463 lines - interfaces
  Read: EventBus.Core.pas    # 522 lines - implementation
  Read: EventBus.Subscribers.pas  # 381 lines - more logic
  Read: EventBus.Helpers.pas # 424 lines - utilities
  # Total: 1790 lines across 4 files

  Impact: AI agents have context windows. With NX Horizon, the AI never loses track of the implementation. With DEB,
   it might forget details from earlier files.

  2. Simpler Mental Model = Fewer AI Mistakes  NX Horizon's simplicity:

  // AI only needs to understand this pattern:
  var Sub: INxEventSubscription;
  Sub := NxHorizon.Instance.Subscribe<TMyEvent>(Handler, Delivery);
  // ... later
  Sub.WaitFor;

  DEB's complexity:

  // AI must understand:
  // - Attributes with parameters
  // - Two event types (interface + channels)
  // - Context strings
  // - Registration for events vs channels
  [Subscribe(TThreadMode.Main, 'Context:Special')]
  procedure OnEvent(AEvent: IEvent);
  [Channel('MY_CHANNEL')]
  procedure OnMessage(AMsg: string);
  // Plus: RegisterSubscriberForEvents vs RegisterSubscriberForChannels

  Impact: AI makes fewer errors with simpler patterns.

  3. Explicit Code = Better AI Reasoning  NX Horizon (explicit):

  type
    TInvoiceCreatedEvent = record
      InvoiceID: Integer;
      CustomerID: Integer;
    end;

  // AI can see exactly what data is passed
  procedure HandleInvoiceCreated(const AEvent: TInvoiceCreatedEvent);
  begin
    // AI knows AEvent.InvoiceID and AEvent.CustomerID exist
    DoSomething(AEvent.InvoiceID);
  end;

  DEB (magic strings/interfaces):

  [Channel('INVOICE_CREATED')]
  procedure OnInvoiceMessage(AMsg: string);
  begin
    // AI must guess/ask what's in AMsg
    // Could be JSON, CSV, number, anything
    var Data := ParseJSON(AMsg); // AI unsure of structure
  end;

  4. Type Safety = AI Autocomplete/Validation  NX Horizon helps AI help you:

  // AI can validate at "coding time"
  var Event: TInvoiceEvent;
  Event.InvoiceID := 123;     // ✓ AI knows this field exists
  Event.WrongField := 'test';  // ✗ AI catches this error immediately

  DEB's interfaces require more context:

  // AI needs to find interface definition elsewhere
  procedure OnEvent(AEvent: IInvoiceEvent);
  begin
    AEvent.GetSomething; // AI must look up interface methods
  end;

  5. Predictable Patterns = Better AI Code Generation 

NX Horizon pattern is consistent:

  // AI learns one pattern, applies everywhere
  type TEventX = record Field: Type; end;
  var SubX := Subscribe<TEventX>(HandlerX, Delivery);
  SubX.WaitFor;

  DEB has multiple patterns:

  // AI must choose between:
  // Pattern 1: Interface events with Subscribe attribute
  // Pattern 2: Channel messages with Channel attribute
  // Pattern 3: Context-based routing
  // Pattern 4: Different registration methods

  6. Debugging = AI Can Trace Execution  NX Horizon's single file:

  // AI prompt: "trace what happens when I post TMyEvent"
  // AI can follow the entire flow in one file:
  // Post -> FindSubscriptions -> Dispatch -> Done

  DEB's distributed logic:

  // AI prompt: "trace what happens when I post to 'MY_CHANNEL'"
  // AI must jump between files:
  // EventBus.pas -> Core.pas -> Subscribers.pas -> Helpers.pas
  // May lose context or miss edge cases

  Real AI Coding Scenario Comparison

  Task: "Add event when stock level changes"

  With NX Horizon:

  User: Add an event when stock level changes below minimum

  AI: I'll create a stock level event. Here's the implementation:  1. Define the event type:

  type
    TStockLevelLowEvent = record
      ProductID: Integer;
      CurrentLevel: Integer;
      MinimumLevel: Integer;
      WarehouseID: Integer;
    end;

  2. Subscribe in the UI:

  fStockSub := NxHorizon.Instance.Subscribe<TStockLevelLowEvent>(
    HandleStockLow, TNxHorizonDelivery.MainAsync);

  3. Post from business logic:

  var Event: TStockLevelLowEvent;
  Event.ProductID := 123;
  Event.CurrentLevel := 5;
  Event.MinimumLevel := 10;
  NxHorizon.Instance.Post(Event);

  AI has complete confidence - all code verified against single file,

  ### With DEB:
  User: Add an event when stock level changes below minimum

  AI: I'll add a stock level event. Let me check the pattern...

  [AI reads EventBus.pas]
  Should I use interface or channel?

  [AI reads EventBus.Core.pas]
  How do contexts work?

  [Channel('STOCK_LOW')]  // Or should it be [Subscribe]?
  procedure OnStockLow(AMsg: string); // Or IStockEvent?

  AI uncertain - needs clarification on which pattern to use.

  Critical Advantage: AI Can Generate Tests  NX Horizon - AI generates complete test:

  // AI can generate this because it understands the entire flow
  procedure TestStockEvent;
  var
    Event: TStockLevelLowEvent;
    Received: Boolean;
  begin
    NxHorizon.Instance.Subscribe<TStockLevelLowEvent>(
      procedure(const E: TStockLevelLowEvent)
      begin
        Assert(E.ProductID = 123);
        Received := True;
      end,
      TNxHorizonDelivery.Sync
    );

    Event.ProductID := 123;
    NxHorizon.Instance.Post(Event);
    Assert(Received);
  end;

  DEB - AI struggles with test generation:
  - Which registration method?
  - How to mock attributes?
  - Context strings?
  - Channel vs interface events?

  Recommendation for AI-Assisted Development

  Choose NX Horizon because:

  1. Single file = AI never loses context
  2. Simple patterns = AI makes fewer mistakes
  3. Explicit types = AI can validate code
  4. Predictable = AI generates correct code first time
  5. Testable = AI can write comprehensive tests  Mitigation for UI scenarios: Create a thin wrapper that adds the conveniences you need:

  type
    TUIEventBus = class
      class procedure Subscribe<T>(AForm: TForm; AHandler: TProc<T>);
      class procedure Post<T>(const AEvent: T);
    end;

  This gives you NX Horizon's AI-friendliness with UI-specific conveniences.

  Bottom line: When working with AI agents, code simplicity and explicitness matter more than features. NX Horizon's
   single-file, explicit approach makes it the clear winner for AI-assisted development.

Share this post


Link to post

The purported disadvantage of NxHorizon needing more boilerplate code can be mitigated somewhat if you have the AI write the boilerplate.

  • Like 1

Share this post


Link to post
3 hours ago, Dave Novo said:

The purported disadvantage of NxHorizon needing more boilerplate code can be mitigated somewhat if you have the AI write the boilerplate.

In my use case (diving deeply on AI coding agents), the AI would wirte the boilerplate, and most/all the non-boilerplate code

And the strong typing of NxHorizon would then be an advantage

Edited by Javier Tarí
adding some details

Share this post


Link to post

When it comes to NX Horizon implementation, it is its simplicity and "lack" of some features what makes it both fast and thread-safe. 

 

Because it is simple, it can also be easily adapted or extended according to particular needs. For instance, adding channels can be done by adding thread-safe dictionary which would hold multiple event bus instance, one for each channel besides the default one.

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×