Varelen.Mimoria.Client 0.0.1-alpha2

This is a prerelease version of Varelen.Mimoria.Client.
There is a newer prerelease version of this package available.
See the version list below for details.
dotnet add package Varelen.Mimoria.Client --version 0.0.1-alpha2
                    
NuGet\Install-Package Varelen.Mimoria.Client -Version 0.0.1-alpha2
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Varelen.Mimoria.Client" Version="0.0.1-alpha2" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Varelen.Mimoria.Client" Version="0.0.1-alpha2" />
                    
Directory.Packages.props
<PackageReference Include="Varelen.Mimoria.Client" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Varelen.Mimoria.Client --version 0.0.1-alpha2
                    
#r "nuget: Varelen.Mimoria.Client, 0.0.1-alpha2"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Varelen.Mimoria.Client@0.0.1-alpha2
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Varelen.Mimoria.Client&version=0.0.1-alpha2&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=Varelen.Mimoria.Client&version=0.0.1-alpha2&prerelease
                    
Install as a Cake Tool

mimoria

Build and Test Publish Docker image NuGet Version Docker Image Version GitHub License

Modern and performant cross-platform distributed key-value cache server written in .NET 9.

Currently under development.

Content

Features

  • structured data (key-value, list, json, binary, map, counter)
    • list has optional per value expiration
  • publish and subscribe (built-in channels like key expiration, deletion, list added)
  • good test coverage (unit, integration and system) and asserts
  • metrics built-in with support for Azure Application Insights
  • cluster support for primary and secondary servers (WIP)
    • synchronous replication
    • asynchronous replication
  • client libraries
    • C# (with micro caching and DI support)
    • TypeScript/Node
    • Rust
  • json and binary object serialization
  • cross platform (Windows, Linux, macOS and ARM)
  • retry policies and resilience for
    • connect and auto reconnect
    • operation response timeout
    • built-in exponential and linear retry policy
  • IPv4 and IPv6 support

Installation server

Quickstart

You can run the server with Docker based on the main branch:

docker run -p 6565:6565 --name mimoria -e MIMORIA__PASSWORD=PleaseChooseAVeryLongOne varelen/mimoria:main

To change the port:

docker run -p 50000:50000 --name mimoria -e MIMORIA__PORT=50000 -e MIMORIA__PASSWORD=PleaseChooseAVeryLongOne varelen/mimoria:main

See the config section for more options.

Manual

From source

Installation client

You can install the .NET client library from Nuget:

dotnet add package Varelen.Mimoria.Client

C# client examples

Using dotnet dependency injection (IServiceCollection):

// ...

builder.Services.AddMimoria(options =>
{
    options.Host = "localhost";
    options.Port = 6565;
    options.OperationTimeout = TimeSpan.FromMilliseconds(250);
    options.ConnectRetryPolicy = new ExponentialRetryPolicy(initialDelay: 1000, maxRetries: 4, typeof(TimeoutException));
    options.OperationRetryPolicy = new ExponentialRetryPolicy<IByteBuffer>(initialDelay: 1000, maxRetries: 4, typeof(TimeoutException));
});

// The "IMimoriaClient" interface can then be injected and be used

Single instance:

IMimoriaClient mimoriaClient = new MimoriaClient("127.0.0.1", 6565, "password");

await mimoriaClient.ConnectAsync();

await mimoriaClient.SetStringAsync("key", "Hello!", ttl: TimeSpan.FromMinutes(5));

string? value = await mimoriaClient.GetStringAsync("key");
Console.WriteLine(value);
// Outputs:
// Hello!

Stats stats = await mimoriaClient.GetStatsAsync();
Console.WriteLine(stats);
// Outputs:
// Uptime: 6, Connections: 1, CacheSize: 1, CacheHits: 1, CacheMisses: 0, CacheHitRatio: 1 (100%)

Pub Sub with add list subscription and expiring list value:

IMimoriaClient mimoriaClient = new MimoriaClient("127.0.0.1", 6565, "password");
await mimoriaClient.ConnectAsync();

var subscription = await mimoriaClient.SubscribeAsync(Channels.ForListAdded("elements"));
subscription.Payload += HandleListAdded;

static void HandleListAdded(MimoriaValue payload)
{
    string element = payload!;

    Console.WriteLine($"Added to the elements list: {element}");
}

await mimoriaClient.AddListAsync("elements", "Water");
await mimoriaClient.AddListAsync("elements", "Air", ttl: default, valueTtl: TimeSpan.FromSeconds(1));

await Task.Delay(TimeSpan.FromSeconds(2));

List<string> list = await mimoriaClient.GetListAsync("elements");
// List only contains 'Water'

Cluster servers (primary and secondaries):

var clusterMimoriaClient = new ClusterMimoriaClient("password", [
    new IPEndPoint(IPAddress.Parse("127.0.0.1"), 6565),
    new IPEndPoint(IPAddress.Parse("127.0.0.1"), 6567),
    new IPEndPoint(IPAddress.Parse("127.0.0.1"), 6569)
]);

await clusterMimoriaClient.ConnectAsync();

await clusterMimoriaClient.SetStringAsync("key", "valueeeee");

string? value = await clusterMimoriaClient.GetStringAsync("key", preferSecondary: true);
Console.WriteLine(value);
// Outputs (if using sync replication):
// some value

Sharded servers:

IShardedMimoriaClient shardedMimoriaClient = new ShardedMimoriaClient(
    "password", new IPEndPoint(IPAddress.Loopback, 6565), new IPEndPoint(IPAddress.Loopback, 6666));

await shardedMimoriaClient.ConnectAsync();

await shardedMimoriaClient.SetStringAsync("key", "some value");
string? value = await shardedMimoriaClient.GetStringAsync("key");
Console.WriteLine(value);
// Outputs:
// some value

Fast custom binary object serialization:

Guid userId = Guid.Parse("9d9b9548-3c34-415b-98c9-cb3bcfd56392");
var user = new User { Id = userId, Byte = 5, Name = "User 1" };

await mimoriaClient.SetObjectBinaryAsync($"user:{userId}", user);

User? responseUser = await mimoriaClient.GetObjectBinaryAsync<User>($"user:{userId}");
Console.WriteLine(responseUser)
// Outputs:
// Id: 9d9b9548-3c34-415b-98c9-cb3bcfd56392, Byte: 5, Name: User 1

public class User : IBinarySerializable
{
    public Guid Id { get; set; }
    public byte Byte { get; set; }
    public string Name { get; set; }
    
    public void Serialize(IByteBuffer byteBuffer)
    {
        byteBuffer.WriteGuid(this.Id);
        byteBuffer.WriteByte(this.Byte);
        byteBuffer.WriteString(this.Name);
    }

    public void Deserialize(IByteBuffer byteBuffer)
    {
        this.Id = byteBuffer.ReadGuid();
        this.Byte = byteBuffer.ReadByte();
        this.Name = byteBuffer.ReadString()!;
    }

    public override string ToString()
        => $"Id: {this.Id}, Byte: {this.Byte}, Name: {this.Name}";
}

Json object serialization:

Guid userId = Guid.Parse("9d9b9548-3c34-415b-98c9-cb3bcfd56392");
var user = new User { Id = userId, Byte = 5, Name = "User 1" };

await mimoriaClient.SetObjectJsonAsync<User>($"user:{userId}", user);

User? responseUser = await mimoriaClient.GetObjectJsonAsync<User>($"user:{userId}");
Console.WriteLine(responseUser);
// Outputs:
// Id: 9d9b9548-3c34-415b-98c9-cb3bcfd56392, Byte: 5, Name: User 1

Both SetObjectJsonAsync and GetObjectJsonAsync have an overload that can take an optional System.Text.Json.JsonSerializerOptions:

var jsonSerializerOptions = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };

await mimoriaClient.SetObjectJsonAsync<User>($"user:{myUserId}", user, jsonSerializerOptions);

_ = await mimoriaClient.GetObjectJsonAsync<User>($"user:{myUserId}", jsonSerializerOptions);

Config

Options can aslo be set via environment variables with two underscores as separators. List can be set with double underscores and the index.

Some examples:

MIMORIA__PASSWORD=PleaseChooseAVeryLongOne

MIMORIA__CLUSTER__ID=1

MIMORIA__CLUSTER__NODES__0__ID=2

Example of all config options:

{
    "Mimoria": {
        "Ip": "0.0.0.0",
        "Port": 6565,
        "Password": "password",
        "Cluster": {
            "Id": 1,
            "Ip": "127.0.0.1",
            "Port": 6566,
            "Password": "YourClusterPassword",
            "Nodes": [
                {
                    "Id": 2,
                    "Host": "127.0.0.2",
                    "Port": 6568
                }
            ],
            "Replication": {
                "Type": "Async",
                "IntervalMilliseconds": 5000
            },
            "Election": {
                "LeaderHeartbeatIntervalMs": 1000,
                "LeaderMissingTimeoutMs": 3000,
                "ElectionTimeoutMs": 1000
            }
        }
    },
    "ConnectionStrings": {
        "ApplicationInsights": "OptionalApplicationInsightsConnectionString"
    },
    "Logging": {
        "LogLevel": {
            "Default": "Information",
            "System": "Information",
            "Microsoft": "Warning"
        }
    }
}

Contributing

Any contributions are greatly appreciated. Just fork the project, create a new feature branch, commit and push your changes and open a pull request.

License

Distributed under the MIT License. See LICENSE for more information.

Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 is compatible.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.0.1-alpha6 191 4/23/2025
0.0.1-alpha5 144 4/22/2025
0.0.1-alpha4 113 4/18/2025
0.0.1-alpha3 126 4/1/2025
0.0.1-alpha2 159 3/30/2025
0.0.1-alpha1 119 3/27/2025