Skip to content

EomTaeWook/Dignus.ActorServer.Rust

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

9 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Dignus.ActorServer.Rust

Rust port of the Dignus Actor Framework.

This repository is a work-in-progress port of the original C# Dignus.ActorServer project to Rust.

The goal is to keep the original actor runtime design as close as possible while adapting the implementation to Rust ownership, threading, and module rules.


Porting Target

Original C# project:

Dignus.ActorServer
├─ Dignus.Actor.Abstractions
├─ Dignus.Actor.Core
├─ Dignus.Actor.Network
└─ Benchmark

Rust port target:

Dignus.ActorServer.Rust
├─ actor-core
├─ actor-network
└─ benchmark

Current workspace status:

Dignus.ActorServer.Rust
└─ actor-core

Design Direction

The Rust implementation follows these rules:

  • Keep the original C# structure where practical
  • Avoid unnecessary abstraction during porting
  • Prefer direct Rust equivalents over redesign
  • Use Rust modules instead of C# namespaces
  • Use Arc, Mutex, atomics, and thread-local storage where required
  • Keep dispatcher execution dedicated to worker threads
  • Hide runtime-only internals where Rust module visibility allows it

C# to Rust Mapping

C# Rust
namespace mod
internal pub(crate)
interface trait
abstract class trait + ActorContext
IDisposable explicit dispose()
[ThreadStatic] thread_local!
SemaphoreSlim custom Signal
Thread std::thread::JoinHandle
volatile bool AtomicBool
Interlocked atomic operations
ObjectPoolBase<T> Mutex<Vec<Arc<T>>> based pool
SendOrPostCallback + state FnOnce() closure
SynchronizationContext.Post dispatcher continuation scheduling

Actor Runtime Flow

The dispatcher keeps the original execution idea:

Post message
   ↓
Enqueue ActorMail
   ↓
Schedule ActorRunner on owner dispatcher
   ↓
Signal dispatcher thread
   ↓
Dispatcher drains scheduled queue
   ↓
ActorRunner creates and polls actor receive future
   ↓
Actor handles message

If the receive future returns Pending, mailbox processing for that actor is stopped until the pending receive future completes.


Dispatcher Context Switching

The C# version supports dispatcher switching through:

await ActorAwait.Join(actor);

The Rust port keeps the same concept:

ActorAwait::join(actor).await;

This schedules the continuation onto the target actor dispatcher.

ActorAwait::join(target).await is a dispatcher context switch. It does not transfer actor ownership. If actor state is accessed after a dispatcher switch, the actor implementation is responsible for returning to the correct dispatcher or validating the context.


Actor Receive Await Model

The Rust port keeps the C# actor continuation model where practical.

ActorBase::on_receive may return a future that borrows actor state across await points. This allows actor implementations to keep a C#-like flow:

on_receive
   ↓
access actor state
   ↓
await
   ↓
continue receive logic
   ↓
access actor state again

When a receive continuation is moved to another dispatcher using ActorAwait::join(target).await, actor-owned mutable state should not be accessed unless the continuation has returned to the owning dispatcher or the implementation explicitly validates the context.


Pending Receive Scheduling

Pending receive polling is separated from normal mailbox execution.

Receive future returns Pending
   ↓
Store pending receive future
   ↓
Stop mailbox processing for this actor
   ↓
Wake schedules pending receive task
   ↓
Pending receive task polls only the pending future
   ↓
Ready schedules ActorRunner back to owner dispatcher

A wake does not directly schedule the normal ActorRunner. This prevents mailbox messages from being processed on a dispatcher that only woke the pending receive future.

PendingReceiveState tracks pending receive transitions such as idle, scheduled, polling, and schedule-requested states. This avoids lost wakes and prevents concurrent polling of the same receive future.


Kill Semantics

Kill() changes the actor lifecycle state to killing and rejects new messages.

If the actor currently has a pending receive future, the runtime does not forcibly cancel it. Finalization occurs only after the pending receive future completes and the actor runner returns to the owner dispatcher.

If a receive future never completes, actor finalization also does not complete. This follows the original C# runtime semantics and is considered the actor implementation's responsibility.


Runtime Safety Notes

The runtime relies on the following internal invariants:

  • Only one receive future may be active per actor
  • A pending receive future must not be polled concurrently
  • Mailbox processing is stopped while a receive future is pending
  • Pending receive polling is handled by a pending receive task, not by the normal mailbox runner
  • Pending receive completion schedules the normal actor runner back to the owner dispatcher
  • Actor finalization must not run while a receive future is still pending
  • Actor implementations should validate dispatcher context before accessing actor-owned mutable state after dispatcher switching

Current Core Components

  • ActorSystem

    • owns dispatchers
    • spawns actors
    • routes posts and kills
    • disposes actors and dispatchers
  • ActorBase

    • user-implemented actor trait
    • defines on_receive
    • optionally defines on_kill
  • ActorContext

    • stores runtime actor state
    • owns dispatcher reference
    • owns self actor reference
    • provides context verification
  • ActorRef

    • posts messages
    • posts actor mail
    • kills actor
  • ActorRunner

    • owns actor instance
    • owns mailbox
    • creates actor receive future
    • schedules owner dispatcher mailbox execution
    • finalizes actor kill
  • PendingReceiveState

    • tracks pending receive future state
    • prevents concurrent pending future polling
    • preserves wake requests that occur while polling
  • ActorPendingReceiveTask

    • polls only the stored pending receive future
    • never processes actor mailbox messages
  • ActorDispatcher

    • owns scheduled actor queue
    • owns dispatcher thread
    • runs scheduled actor tasks
  • ActorAwait

    • switches async continuation to another actor dispatcher

Build

From the workspace root:

cargo check

Or from actor-core:

cargo check

Workspace

Root Cargo.toml:

[workspace]
resolver = "2"
members = [
    "actor-core"
]

actor-core/Cargo.toml:

[package]
name = "actor-core"
version = "0.1.0"
edition = "2021"

[dependencies]

Notes

Some C# features do not have direct Rust standard library equivalents.

Examples:

  • abstract class
  • protected
  • SynchronizationContext
  • Thread.Priority
  • Background thread setting
  • C# reference-based object pooling

These are adapted only where the current Rust runtime structure requires them.


License

Licensed under the MIT License.

See LICENSE in the project root.

About

Rust port of Dignus.ActorServer, a high-performance actor-based runtime and network server framework.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages