Categorygithub.com/sosalejandro/ddd-golang/pkg/event-manager
modulepackage
0.0.1-rc
Repository: https://github.com/sosalejandro/ddd-golang.git
Documentation: pkg.go.dev

# README

Event Manager in Go

This package provides an Event Manager implementation for handling domain events within a Go application, adhering to Domain-Driven Design (DDD) principles. It facilitates the registration, existence check, and unmarshalling of events, ensuring a scalable and maintainable event-driven architecture.

Overview

The EventManager is responsible for managing domain events within the application. It allows registering event types, checking for their existence, and unmarshalling event data into corresponding event structures. This ensures that events are consistently handled and processed across different parts of the system.

Getting Started

Prerequisites

  • Go 1.18 or higher installed on your machine.
  • Git for cloning the repository.

Installation

  1. Clone the Repository
git clone https://github.com/sosalejandro/ddd-golang.git
cd ddd-golang/pkg/event-manager
  1. Initialize Go Modules
go mod tidy

Usage

Initializing the Event Manager

Create a new instance of the EventManager:

import "github.com/sosalejandro/ddd-golang/pkg/event-manager"

em := event_manager.NewEventManager()

Registering Events

Register your domain events with the Event Manager:

type BookAddedEvent struct {
    Title string
}

type BookRemovedEvent struct {
    Title string
}

em.RegisterEvents(&BookAddedEvent{}, &BookRemovedEvent{})

Checking Event Existence

Verify if an event type is registered:

exists := em.Exists("BookAddedEvent")
if exists {
    fmt.Println("Event type exists.")
} else {
    fmt.Println("Event type does not exist.")
}

Unmarshalling Events

Convert JSON data into the corresponding event structure:

data := []byte(`{"Title": "1984"}`)
event, err := em.UnmarshalEvent("BookAddedEvent", data)
if err != nil {
    fmt.Println("Error unmarshalling event:", err)
} else {
    fmt.Printf("Unmarshalled Event: %+v\n", event)
}

Using EventManager as a Singleton

The EventManager can be instantiated as a singleton to manage all events across the service. This approach ensures that event registrations are centralized, reducing redundancy and facilitating easier maintenance.

var singletonEventManager = event_manager.NewEventManager()

func GetEventManager() *event_manager.EventManager {
    return singletonEventManager
}

Register all events during the application's initialization phase:

func init() {
    em := GetEventManager()
    em.RegisterEvents(&BookAddedEvent{}, &BookRemovedEvent{})
}

This singleton instance is optimized for scenarios with numerous read operations and minimal write operations, primarily during initialization.

Using EventManager per Aggregate

Alternatively, you can instantiate separate EventManager instances for each aggregate. This approach encapsulates event management within specific aggregates, promoting modularity and separation of concerns.

func NewLibraryEventManager() *event_manager.EventManager {
    em := event_manager.NewEventManager()
    em.RegisterEvents(&BookAddedEvent{}, &BookRemovedEvent{})
    return em
}

Each aggregate interacts with its own EventManager, allowing for tailored event handling and reduced coupling between different parts of the system.

Optimization for Reads Over Writes

The EventManager is designed to be highly efficient for read operations, making it ideal for applications where event retrieval is frequent and event registrations are infrequent. It employs concurrent-safe structures like sync.Map to facilitate fast, lock-free reads.

  • Reads: Optimized using concurrent data structures to allow multiple goroutines to access the registry without contention.
  • Writes: Primarily occur during the initialization phase when registering events. Since writes are minimal and rarely occur after setup, the performance impact is negligible.

This optimization strategy ensures that the EventManager can handle high read loads efficiently while maintaining thread safety.

Example

package main

import (
    "fmt"
    "github.com/sosalejandro/ddd-golang/pkg/event-manager"
)

func main() {
    em := event_manager.NewEventManager()

    // Register events
    em.RegisterEvents(&BookAddedEvent{}, &BookRemovedEvent{})

    // Check event existence
    if em.Exists("BookAddedEvent") {
        fmt.Println("BookAddedEvent is registered.")
    }

    // Unmarshal event data
    data := []byte(`{"Title": "Brave New World"}`)
    event, err := em.UnmarshalEvent("BookAddedEvent", data)
    if err != nil {
        fmt.Println("Error:", err)
    } else {
        fmt.Printf("Received Event: %+v\n", event)
    }
}

type BookAddedEvent struct {
    Title string
}

type BookRemovedEvent struct {
    Title string
}

Handling Unknown Events

If an event type is not registered, the UnmarshalEvent method will return an error. Ensure that all necessary event types are registered before attempting to unmarshal.

event, err := em.UnmarshalEvent("UnknownEvent", data)
if err != nil {
    fmt.Println("Error:", err) // Outputs: unknown event type: UnknownEvent
}

Dependencies

Testing

Unit tests are provided to ensure the correctness of the Event Manager operations.

go test ./pkg/event-manager

Conclusion

The EventManager package offers a robust solution for managing domain events in Go applications. By registering, checking, and unmarshalling events efficiently, it supports the implementation of a clean and maintainable event-driven architecture. Whether used as a singleton or per aggregate, its optimization for read-heavy operations makes it suitable for a wide range of applications.

# Functions

No description provided by the author

# Structs

No description provided by the author
No description provided by the author