From Akka.NET
Это содержимое пока не доступно на вашем языке.
Akka.NET is the .NET port of Akka — runs on .NET / .NET Framework, with the same actor model, clustering, and persistence story.
For migration, Akka.NET ≈ Akka (JVM) — the from-akka-jvm guide covers the conceptual mapping. This page focuses on C# specifics and what changes in TypeScript.
Concept mapping
Section titled “Concept mapping”// Akka.NET (C#):public class Counter : ReceiveActor { private int _count; public Counter() { Receive<string>(command => { if (command == "inc") _count++; else if (command == "get") Sender.Tell(_count); }); }}
var system = ActorSystem.Create("MySystem");var counter = system.ActorOf<Counter>("counter");counter.Tell("inc");// actor-ts:import { match } from 'ts-pattern';import { Actor, ActorSystem, type ActorRef } from 'actor-ts';
type IncrementCommand = { kind: 'increment' };type GetCommand = { kind: 'get'; replyTo: ActorRef<number> };type Command = IncrementCommand | GetCommand;
class Counter extends Actor<Command> { private count = 0; override onReceive(command: Command): void { match(command) .with({ kind: 'increment' }, () => this.onIncrement()) .with({ kind: 'get' }, (c) => this.onGet(c)) .exhaustive(); }
private onIncrement(): void { this.count++; } private onGet(command: GetCommand): void { command.replyTo.tell(this.count); }}
const system = ActorSystem.create('MySystem');const counter = system.spawn(Counter, 'counter');counter.tell({ kind: 'increment' });Differences from Akka.NET:
- No
ReceiveActorbase +Receive<T>registrations — useonReceive(message)with a switch / pattern-match. - Message types are explicit —
Commandunion vs Akka.NET’s often-untypedReceive<object>. - Lambda-style behavior definition isn’t TypeScript-friendly
— class with
onReceiveis the idiom.
Sender / reply
Section titled “Sender / reply”// Akka.NET:Receive<GetState>(_ => Sender.Tell(_state));// actor-ts — option 1: replyTo in the messagetype GetStateCommand = { kind: 'get-state'; replyTo: ActorRef<State> };type Command = GetStateCommand;
class MyActor extends Actor<Command> { onReceive(command: Command): void { match(command) .with({ kind: 'get-state' }, (c) => this.onGetState(c)) .exhaustive(); }
private onGetState(command: GetStateCommand): void { command.replyTo.tell(this.state); }}
// actor-ts — option 2: this.sender (Option type)class MyActor extends Actor<Command> { onReceive(command: Command): void { match(command) .with({ kind: 'get-state' }, () => this.onGetState()) .exhaustive(); }
private onGetState(): void { this.sender.forEach(s => s.tell(this.state)); }}Prefer option 1 (explicit replyTo) — type-safe and clear
about the contract.
Supervisor strategy
Section titled “Supervisor strategy”// Akka.NET:protected override SupervisorStrategy SupervisorStrategy() => new OneForOneStrategy(maxNrOfRetries: 5, withinTimeRange: TimeSpan.FromMinutes(1), decider: ex => ex switch { ArithmeticException _ => Directive.Resume, _ => Directive.Restart, });// actor-ts:override supervisorStrategy = new OneForOneStrategy( decideBy([ { match: TypeError, then: Directive.Resume }, ], Directive.Restart), { maxRetries: 5, withinTimeRangeMs: 60_000 },);Same shape — decider returns directives based on exception type.
Cluster
Section titled “Cluster”// Akka.NET:var cluster = Cluster.Get(system);cluster.Join(Address.Parse("akka.tcp://MySystem@host:port"));// actor-ts:const cluster = await Cluster.join(system, { host: 'host', port: 2552, seeds: ['host:2552', ...],});Same join semantics; actor-ts uses URL-like seeds vs Akka.NET’s explicit Address.
Sharding
Section titled “Sharding”// Akka.NET:var region = ClusterSharding.Get(system).Start( typeName: "Counter", entityProps: Props.Create<CounterActor>(), settings: ClusterShardingSettings.Create(system), messageExtractor: new MessageExtractor());// actor-ts:const region = cluster.sharding.start<Command>({ typeName: 'Counter', entityActor: CounterActor, extractEntityId: (command) => command.entityId, numShards: 100,});Drop-in conceptually. MessageExtractor becomes
extractEntityId; shard ID is auto-derived.
Persistence
Section titled “Persistence”// Akka.NET:public class Account : ReceivePersistentActor { public override string PersistenceId => "account-" + Id; private decimal _balance;
public Account() { Recover<Deposited>(e => _balance += e.Amount);
Command<Deposit>(c => Persist(new Deposited(c.Amount), e => _balance += e.Amount)); }}// actor-ts:class Account extends PersistentActor<Command, Event, State> { constructor(public readonly id: string) { super(); } readonly persistenceId = `account-${this.id}`;
initialState(): State { return { balance: 0 }; }
onEvent(state: State, event: Event): State { return match(event) .with({ kind: 'deposited' }, (e) => ({ balance: state.balance + e.amount })) .exhaustive(); }
onCommand(state: State, command: Command): void { match(command) .with({ kind: 'deposit' }, (c) => this.onDeposit(c)) .exhaustive(); }
private onDeposit(command: DepositCommand): void { this.persist({ kind: 'deposited', amount: command.amount }, () => {}); }}Single onEvent instead of split Recover<T> / Command<T>.
Configuration
Section titled “Configuration”Akka.NET uses HOCON for configuration — same as Akka JVM. actor-ts also uses HOCON (Configuration).
The key prefixes differ:
# Akka.NET:akka { cluster { seed-nodes = [...] failure-detector { ... } }}
# actor-ts:actor-ts { cluster { gossip-interval = 1s failure-detector { ... } }}Different root key (akka vs actor-ts), different specific
keys, but the HOCON format and conventions are the same.
What you give up
Section titled “What you give up”- C# language features — LINQ, async/await with structured concurrency, etc. TypeScript has async/await but the ecosystem is different.
- .NET ecosystem — Akka.NET integrates with .NET’s auth, ORM, etc. ecosystems. actor-ts uses Node / Bun’s.
- Some Akka.NET-specific features — DotNetty transport, Hyperion serialization, etc. don’t have direct equivalents.
What you gain
Section titled “What you gain”- TypeScript types — message types checked at the boundary.
- Faster startup — Bun starts in sub-100ms vs .NET’s ~500ms-1s.
- Container-native — smaller images, less memory baseline.
Migration strategies
Section titled “Migration strategies”Same as Akka JVM:
- Don’t rewrite everything at once. Run actor-ts in a new service that fronts the Akka.NET system.
- One bounded context at a time.
- Migrate persistence carefully — Akka.NET’s JSON.NET serialized events can be read by actor-ts with an EventAdapter.
Where to next
Section titled “Where to next”- from-akka-jvm — the main reference (Akka.NET mirrors JVM Akka).
- Migration overview — cross-framework comparison.
- Quickstart — actor-ts hello world.
