Skip to content

Commit

Permalink
Added shutdown support for struct actors
Browse files Browse the repository at this point in the history
  • Loading branch information
andresgutierrez committed Jul 25, 2024
1 parent b8f0510 commit 952c778
Show file tree
Hide file tree
Showing 4 changed files with 142 additions and 2 deletions.
29 changes: 29 additions & 0 deletions Nixie.Tests/Actors/ShutdownActorStruct.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@

namespace Nixie.Tests.Actors;

public sealed class ShutdownActorStruct : IActorStruct<int>
{
private int receivedMessages;

public ShutdownActorStruct(IActorContextStruct<ShutdownActorStruct, int> _)
{

}

public int GetMessages()
{
return receivedMessages;
}

private void IncrMessage()
{
receivedMessages++;
}

public async Task Receive(int message)
{
await Task.Yield();

IncrMessage();
}
}
46 changes: 46 additions & 0 deletions Nixie.Tests/TestShutdown.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,29 @@ public async Task TestSpawnReplyActorAndShutdownByName()
Assert.Null(actor2);
}

[Fact]
public async Task TestSpawnFireAndForgetActorStructAndShutdownByName()
{
using ActorSystem asx = new();

IActorRefStruct<ShutdownActorStruct, int> actor = asx.SpawnStruct<ShutdownActorStruct, int>("my-actor");

Assert.IsAssignableFrom<ShutdownActorStruct>(actor.Runner.Actor);

actor.Send(100);

await asx.Wait();

Assert.True(asx.ShutdownStruct<ShutdownActorStruct, int>("my-actor"));

await asx.Wait();

Assert.Equal(1, ((ShutdownActorStruct)actor.Runner.Actor!).GetMessages());

IActorRefStruct<ShutdownActorStruct, int>? actor2 = asx.GetStruct<ShutdownActorStruct, int>("my-actor");
Assert.Null(actor2);
}

[Fact]
public async Task TestSpawnFireAndForgetActorAndShutdownByName2()
{
Expand Down Expand Up @@ -156,6 +179,29 @@ public async Task TestSpawnReplyActorAndShutdownByRef()
Assert.Null(actor2);
}

[Fact]
public async Task TestSpawnFireAndForgetActorStructAndShutdownByRef()
{
using ActorSystem asx = new();

IActorRefStruct<ShutdownActorStruct, int> actor = asx.SpawnStruct<ShutdownActorStruct, int>("my-actor");

Assert.IsAssignableFrom<ShutdownActorStruct>(actor.Runner.Actor);

actor.Send(100);

await asx.Wait();

Assert.True(asx.ShutdownStruct(actor));

await asx.Wait();

Assert.Equal(1, ((ShutdownActorStruct)actor.Runner.Actor!).GetMessages());

IActorRefStruct<ShutdownActorStruct, int>? actor2 = asx.GetStruct<ShutdownActorStruct, int>("my-actor");
Assert.Null(actor2);
}

[Fact]
public async Task TestSpawnFireAndForgetActorAndShutdownByRef2()
{
Expand Down
64 changes: 64 additions & 0 deletions Nixie/ActorSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,22 @@ public IActorRefStruct<TActor, TRequest> SpawnStruct<TActor, TRequest>(string? n
return repository.Get(name);
}

/// <summary>
/// Returns a fire-n-forget actor by its name and null if it doesn't exist.
/// </summary>
/// <typeparam name="TActor"></typeparam>
/// <typeparam name="TRequest"></typeparam>
/// <typeparam name="TResponse"></typeparam>
/// <param name="name"></param>
/// <returns></returns>
public IActorRefStruct<TActor, TRequest>? GetStruct<TActor, TRequest>(string name) where TActor : IActorStruct<TRequest>
where TRequest : struct
{
ActorRepositoryStruct<TActor, TRequest> repository = GetRepositoryStruct<TActor, TRequest>();

return repository.Get(name);
}

/// <summary>
/// Shutdowns an actor by its name
/// </summary>
Expand Down Expand Up @@ -217,6 +233,38 @@ public bool Shutdown<TActor, TRequest>(string name) where TActor : IActor<TReque
return repository.Shutdown(name);
}

/// <summary>
/// Shutdowns an actor by its reference
/// </summary>
/// <typeparam name="TActor"></typeparam>
/// <typeparam name="TRequest"></typeparam>
/// <typeparam name="TResponse"></typeparam>
/// <param name="name"></param>
/// <returns></returns>
public bool ShutdownStruct<TActor, TRequest, TResponse>(IActorRefStruct<TActor, TRequest, TResponse> actorRef)
where TActor : IActorStruct<TRequest, TResponse> where TRequest : struct where TResponse : struct
{
ActorRepositoryStruct<TActor, TRequest, TResponse> repository = GetRepositoryStruct<TActor, TRequest, TResponse>();

return repository.Shutdown(actorRef);
}

/// <summary>
/// Shutdowns an actor by its name
/// </summary>
/// <typeparam name="TActor"></typeparam>
/// <typeparam name="TRequest"></typeparam>
/// <typeparam name="TResponse"></typeparam>
/// <param name="name"></param>
/// <returns></returns>
public bool ShutdownStruct<TActor, TRequest>(string name) where TActor : IActorStruct<TRequest>
where TRequest : struct
{
ActorRepositoryStruct<TActor, TRequest> repository = GetRepositoryStruct<TActor, TRequest>();

return repository.Shutdown(name);
}

/// <summary>
/// Shutdowns an actor by its reference
/// </summary>
Expand All @@ -233,6 +281,22 @@ public bool Shutdown<TActor, TRequest>(IActorRef<TActor, TRequest> actorRef)
return repository.Shutdown(actorRef);
}

/// <summary>
/// Shutdowns an actor by its reference
/// </summary>
/// <typeparam name="TActor"></typeparam>
/// <typeparam name="TRequest"></typeparam>
/// <typeparam name="TResponse"></typeparam>
/// <param name="name"></param>
/// <returns></returns>
public bool ShutdownStruct<TActor, TRequest>(IActorRefStruct<TActor, TRequest> actorRef)
where TActor : IActorStruct<TRequest> where TRequest : struct
{
ActorRepositoryStruct<TActor, TRequest> repository = GetRepositoryStruct<TActor, TRequest>();

return repository.Shutdown(actorRef);
}

/// <summary>
/// Returns the repository where the current references to request/response actors are stored.
/// </summary>
Expand Down
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@ Nixie is a lightweight, high-performance implementation of the [actor model](htt

## Features

- **Strongly-Typed Actors:** Ensuring that your actor interactions are type-safe and as per expectations. High use of [generics](https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/types/generics) to avoid as much unnecessary boxing/unboxing as possible.
- **Strongly-Typed Actors:** Ensuring that your actor interactions are type-safe and as per expectations. High use of [generics](https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/types/generics) to ensure that errors related to type mismatches are caught at compile time rather than at runtime. This reduces the risk of runtime exceptions and makes the code more robust.
- **Nullable Support:** Full support for [nullability](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/nullable-reference-types) in line with the latest C# features, ensuring your code is robust and safeguarded against null reference issues.
- **Lifecycle Management:** Nixie handles the meticulous management of actor lifecycle, allowing developers to focus on implementing logic.
- **High Performance:** Thanks to being lightweight and leveraging the powerful TPL, Nixie ensures that your actor systems are both scalable and performant.
- **High Performance:** Thanks to being lightweight and leveraging the powerful TPL, Nixie ensures that your actor systems are both scalable and performant. Additionally the use of Generics eliminate the need for boxing and unboxing when working with value types, which can improve performance. Boxing is the process of converting a value type to an object type, and unboxing is the reverse.
- **Less Error Prone:** The strongly-typed nature and nullability checks inherently make your actor system more reliable and resilient.
- **Built on TPL:** Make the most out of the robust, scalable, and performant asynchronous programming features offered by TPL.
- **Multi-Threading:** To increase throughput, Nixie makes use of thread-safe structures that avoid locks wherever possible and use fine-grained locking where locks are necessary. Abstracting the complexities of multithreaded programming into an API that is easy to use and understand.
- **Production-Ready:** Nixie has been tested in production environments with many concurrent users, ensuring reliability and stability under real-world conditions.

## Getting Started

Expand Down

0 comments on commit 952c778

Please sign in to comment.