Skip to content

Commit

Permalink
minor updates
Browse files Browse the repository at this point in the history
  • Loading branch information
mizrael committed Jun 20, 2024
1 parent 8bc5fc2 commit fe37fef
Show file tree
Hide file tree
Showing 7 changed files with 55 additions and 17 deletions.
Binary file added docs/assets/sensor_details.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/assets/sensors.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/assets/stream_details.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/assets/streams_archive.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
58 changes: 45 additions & 13 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,19 @@ Honestly, I don't know how far this project will go, but I'm having a lot of fun

## How does it work?

The basic idea behind Evenire is quite simple: events can be appended to stream and later on, retrieved by providing the stream ID.
The basic idea behind Evenire is quite simple: events can be appended to streams and later on, retrieved by providing the stream ID.

Streams are identified by a tuple composed by a `Guid` and a string representing a stream type (more details [here](./src/EvenireDB.Common/StreamId.cs)).

Every stream is kept in memory using a local cache, for fast retrieval. A background process takes care of serializing events to a file, one per stream.

Reading can happen from the very beginning of a stream moving forward or from a specific point. This is the basic scenario, useful when you want to rehydrate the state of an [Aggregate](https://www.martinfowler.com/bliki/DDD_Aggregate.html).

Another option is to read the events from the _end_ of the stream instead, moving backwards in time. This is interesting for example if you are recording data from sensors and you want to retrieve the latest state.

# Setup
Autentication was **left out intentionally** as it would go outside the scope of the project (for now).

## Setup

As of now, there are two possible options for spinning up an Evenire server:
- deploying the [Server project](https://github.com/mizrael/EvenireDB/tree/main/src/EvenireDB.Server) somewhere
Expand All @@ -33,26 +37,42 @@ These are both viable options, however, I would recommend opting for the Docker

Once you have the image ready, you can run it in a Container by running `docker compose up`.

# Client configuration
## Client configuration

Once your server is up, you can start using it to store your events. If you are writing a .NET application, you can leverage [the Client library](https://github.com/mizrael/EvenireDB/tree/main/src/EvenireDB.Client) I provided.

Configuration is pretty easy, just add this to your `Program.cs` or `Startup.cs` file:
Client configuration is pretty easy. The first step is to update your `appsettings.json` file and add a new section:
```json
{
"Evenire": {
"ServerUri": "[your server url here]",
"HttpSettings": {
"Port": 80 <---- make sure this is correct for you
},
"GrpcSettings": {
"Port": 5243 <---- make sure this is correct for you
}
}
}
```

Once you have that, the last step is to register EvenireDB on your DI container. Something like this:

```csharp
var builder = WebApplication.CreateBuilder(args);

var connectionString = new Uri(builder.Configuration.GetConnectionString("evenire"));
var clientConfig = builder.Configuration.GetSection("Evenire").Get<EvenireClientConfig>();

builder.Services.AddEvenireDB(new EvenireConfig(connectionString, useGrpc: true));
builder.Services.AddEvenireDB(clientConfig);
```

## Writing events
### Writing events

Once you have added the Client to your IoC Container, just inject `IEventsClient` into your classes and start making calls to it:
Once you have added the Client to your DI Container, just inject `IEventsClient` into your classes and start making calls to it:

```csharp
var streamId = Guid.NewGuid();
var streamKey = /* this is a GUID */;
var streamId = new StreamId(streamKey, "MyStreamType");

await _eventsClient.AppendAsync(streamId, new[]
{
Expand All @@ -61,12 +81,13 @@ await _eventsClient.AppendAsync(streamId, new[]
});
```

## Reading events
### Reading events

Reading too can be done trough an `IEventsClient` instance:

```csharp
var streamId = Guid.NewGuid();
var streamKey = /* this is a GUID */;
var streamId = new StreamId(streamKey, "MyStreamType");

// write some events for streamId...
Expand All @@ -77,10 +98,21 @@ await foreach(var @event in client.ReadAsync(streamId, StreamPosition.Start, Dir

`ReadAsync` can be configured to fetch the events from `StreamPosition.Start`, `StreamPosition.End` or a specific point in the stream. You can also specify the direction you want to move (forward or backward).

# Samples
## Admin UI
Evenire also has a rudimentary administration UI, written with Blazor. It allows a few basic operations:
- see the list of all the available streams
- create a new stream
- append events to an existing stream
- delete a stream

![streams archive](./docs/assets/streams_archive.jpg)

![stream details](./docs/assets/stream_details.jpg)

## Samples
- [TemperatureSensors](https://github.com/mizrael/EvenireDB/tree/main/samples/EvenireDB.Samples.TemperatureSensors) shows how to use a Background worker to produce events and uses Minimal APIs to retrieve the latest events for a specific stream.

# TODO
## TODO
- snapshots
- backup and replicas
- cluster management
Expand Down
10 changes: 10 additions & 0 deletions samples/EvenireDB.Samples.TemperatureSensors/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# TemperatureSensors
This sample shows how to use a [Background worker](./SensorsFakeProducer.cs) to publish `ReadingReceived` for each temperature sensor. Two GET endpoints are exposed to retrieve the list of available sensors and its relative details.

The list of available sensors can be retrieved via GET request at `/sensors`:
![Sensors list](../../docs/assets/sensors.jpg)

Sensor-specific details can be pulled via GET request at `/sensors/[sensor ID]`:
![Sensor details](../../docs/assets/sensor_details.jpg)

When querying for a sensor's details, the list of events for that stream is pulled from the API in backward order (newest first) and aggregated to calculate the average temperature.
4 changes: 0 additions & 4 deletions src/EvenireDB.AdminUI/Shared/MainLayout.razor
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,6 @@
</div>

<main>
<div class="top-row px-4">
<a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a>
</div>

<article class="content px-4">
@Body
</article>
Expand Down

0 comments on commit fe37fef

Please sign in to comment.