Skip to content

IEventStoreConnection

IEventStoreConnection es una interfaz que define el contrato para conectar e interactuar con una instancia de EventStore. EventStore es una base de datos especializada en el almacenamiento de eventos, utilizada comúnmente en arquitecturas de Event Sourcing y CQRS.

La interfaz se utiliza para abstraer la lógica de conexión y manejo de eventos con EventStore. Permite a los desarrolladores inicializar conexiones, manejar eventos de conexión y desconexión, y gestionar errores y autenticaciones fallidas de manera uniforme y desacoplada del cliente específico de EventStore.

Funcionalidades


  1. Inicialización de la Conexión:

    • Task<ES.IEventStoreConnection> InitializeAsync(Server server): Inicializa la conexión a EventStore utilizando los detalles del servidor proporcionados. Este método es asíncrono y devuelve una instancia de IEventStoreConnection inicializada.
  2. Manejo de Eventos:

    • Connected: Evento que se dispara cuando la conexión a EventStore se establece correctamente.
    • Disconnected: Evento que se dispara cuando la conexión a EventStore se desconecta.
    • Reconnecting: Evento que se dispara cuando la conexión a EventStore está intentando reconectarse.
    • Closed: Evento que se dispara cuando la conexión a EventStore se cierra.
    • ErrorOccurred: Evento que se dispara cuando ocurre un error en la conexión a EventStore.
    • AuthenticationFailed: Evento que se dispara cuando la autenticación a EventStore falla.

Características


  • Asincronía: La inicialización de la conexión es asíncrona, lo que permite una mejor gestión de recursos y evita bloqueos en el hilo principal.
  • Manejo de Eventos: Proporciona eventos para manejar diferentes estados de la conexión, lo que permite a los desarrolladores reaccionar adecuadamente a cambios en el estado de la conexión.
  • Abstracción: Al ser una interfaz, permite la implementación de diferentes estrategias de conexión y facilita la prueba unitaria mediante el uso de mocks.

Implementación


La interfaz IEventStoreConnection se implementa en la clase EventStoreConnection, que proporciona la lógica para inicializar y gestionar la conexión a EventStore. La clase EventStoreConnection se encuentra en el espacio de nombres CodeDesignPlus.Net.EventStore.Services.

namespace CodeDesignPlus.Net.EventStore.Services;
/// <summary>
/// Represents a connection to the EventStore.
/// </summary>
/// <remarks>
/// This class is responsible for initializing and managing the connection to the EventStore.
/// </remarks>
public class EventStoreConnection : IEventStoreConnection
{
private readonly CoreOptions coreOptions;
private readonly ILogger<EventStoreConnection> logger;
/// <summary>
/// Initializes a new instance of the <see cref="EventStoreConnection"/> class.
/// </summary>
/// <param name="coreOptions">The core options.</param>
/// <param name="logger">The logger instance.</param>
/// <exception cref="ArgumentNullException">
/// Thrown when <paramref name="coreOptions"/> or <paramref name="logger"/> is null.
/// </exception>
public EventStoreConnection(IOptions<CoreOptions> coreOptions, ILogger<EventStoreConnection> logger)
{
ArgumentNullException.ThrowIfNull(coreOptions);
ArgumentNullException.ThrowIfNull(logger);
this.coreOptions = coreOptions.Value;
this.logger = logger;
this.logger.LogInformation("EventStoreConnection initialized.");
}
/// <summary>
/// Initializes the EventStore connection asynchronously.
/// </summary>
/// <param name="server">The server configuration.</param>
/// <returns>The initialized EventStore connection.</returns>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="server"/> is null.</exception>
public async Task<ES.IEventStoreConnection> InitializeAsync(Server server)
{
ArgumentNullException.ThrowIfNull(server);
var settings = ES.ConnectionSettings.Create()
.SetClusterGossipPort(server.ConnectionString.Port)
.DisableTls()
.UseConsoleLogger()
.KeepReconnecting()
.KeepRetrying();
var connection = ES.EventStoreConnection.Create(settings, server.ConnectionString, this.coreOptions.AppName);
connection.Connected += Connected;
connection.Disconnected += Disconnected;
connection.Reconnecting += Reconnecting;
connection.Closed += Closed;
connection.ErrorOccurred += ErrorOccurred;
connection.AuthenticationFailed += AuthenticationFailed;
await connection.ConnectAsync().ConfigureAwait(false);
this.logger.LogInformation("Successfully connected to EventStore.");
return connection;
}
/// <summary>
/// Handles the authentication failed event.
/// </summary>
/// <param name="sender">The event sender.</param>
/// <param name="e">The event arguments containing the reason for failure.</param>
private void AuthenticationFailed(object sender, ES.ClientAuthenticationFailedEventArgs e)
{
this.logger.LogError("Authentication failed in EventStore: {Reason}", e.Reason);
}
/// <summary>
/// Handles the error occurred event.
/// </summary>
/// <param name="sender">The event sender.</param>
/// <param name="e">The event arguments containing the exception.</param>
private void ErrorOccurred(object sender, ES.ClientErrorEventArgs e)
{
this.logger.LogError(e.Exception, "Error occurred in EventStore: {Exception}", e.Exception.Message);
}
/// <summary>
/// Handles the connection closed event.
/// </summary>
/// <param name="sender">The event sender.</param>
/// <param name="e">The event arguments containing the reason for closure.</param>
private void Closed(object sender, ES.ClientClosedEventArgs e)
{
this.logger.LogInformation("EventStore connection closed: {Reason}", e.Reason);
}
/// <summary>
/// Handles the reconnecting event.
/// </summary>
/// <param name="sender">The event sender.</param>
/// <param name="e">The event arguments.</param>
private void Reconnecting(object sender, ES.ClientReconnectingEventArgs e)
{
this.logger.LogInformation("Reconnecting to EventStore");
}
/// <summary>
/// Handles the disconnected event.
/// </summary>
/// <param name="sender">The event sender.</param>
/// <param name="e">The event arguments.</param>
private void Disconnected(object sender, ES.ClientConnectionEventArgs e)
{
this.logger.LogInformation("EventStore connection disconnected.");
}
/// <summary>
/// Handles the connected event.
/// </summary>
/// <param name="sender">The event sender.</param>
/// <param name="e">The event arguments.</param>
private void Connected(object sender, ES.ClientConnectionEventArgs e)
{
this.logger.LogInformation("EventStore connection established.");
}
}

Ejemplo


Una vez que se ha implementado la interfaz IEventStoreConnection, se puede utilizar para inicializar una conexión a EventStore y manejar eventos de conexión y desconexión.

  1. Agregar las propiedades de configuración al archivo appsettings.json:

    {
    "EventStore": {
    "Servers": {
    "Core": {
    "ConnectionString": "tcp://localhost:1113?tls=false",
    "User": "admin",
    "Password": "12345678"
    }
    }
    }
    }
  2. Registrar la interfaz IEventStoreConnection en el contenedor de dependencias:

    public class Startup
    {
    public void ConfigureServices(IServiceCollection services)
    {
    services.AddSingleton<IEventStoreConnection, EventStoreConnection>();
    services.AddLogging();
    }
    }
  3. Inicializar la conexión a EventStore en una clase de servicio:

    public class EventStoreService
    {
    private readonly IEventStoreConnection eventStoreConnection;
    private readonly EventStoreOptions eventStoreOptions;
    public EventStoreService(IEventStoreConnection eventStoreConnection, IOptions<EventStoreOptions> options)
    {
    this.eventStoreConnection = eventStoreConnection;
    this.eventStoreOptions = options.Value;
    }
    public async Task SaveEventAsync<TEvent>(TEvent @event)
    {
    var connection = await eventStoreConnection.InitializeAsync(eventStoreOptions.Servers["Core"]);
    var eventData = new ES.EventData(
    Guid.NewGuid(),
    "eventType",
    true,
    Encoding.UTF8.GetBytes(JsonSerializer.Serialize(@event)),
    null);
    await connection.AppendToStreamAsync("streamName", ES.ExpectedVersion.Any, eventData);
    }
    }

Conclusiones


La interfaz IEventStoreConnection es esencial para cualquier aplicación que utilice EventStore, proporcionando una manera estructurada y eficiente de manejar conexiones y eventos relacionados. Su implementación permite una gestión robusta de la conexión, asegurando que la aplicación pueda reaccionar adecuadamente a cualquier cambio en el estado de la conexión.