actors 0.7.0-nullsafety.0 actors: ^0.7.0-nullsafety.0 copied to clipboard
Actors Model library for Dart. It is a thin wrapper around Dart's `Isolate` that makes them much easier to use.
actors #
actors
is a library that enables the use of the Actors Model in Dart.
It is a thin wrapper around Dart's Isolate
(on Flutter and Dart VM) that makes them much easier to use.
Actor #
To start an Actor is very easy. You simply create a Handler
implementing the logic to handle messages within the
Actor's Isolate, then create an Actor
using it:
class Two with Handler<int, int> {
int handle(int n) => n * 2;
}
main() async {
final actor = Actor(Two());
print(await actor.send(5)); // 10
await actor.close();
}
If your actor does not maintain internal state, it can also be created from a function:
Due to limitations of
Isolate
, the function must be a top-level function, i.e. not a lambda.
int two(int n) => n * 2;
main() async {
final actor = Actor.of(two);
print(await actor.send(5)); // 10
await actor.close();
}
As you can see, an Actor
can send a message back to the caller asynchronously.
They can also send more than one message by returning a Stream
:
// A Handler that returns a Stream must use a StreamActor, not an Actor.
class StreamGenerator with Handler<int, Stream<int>> {
@override
Stream<int> handle(int message) {
return Stream.fromIterable(Iterable.generate(message, (i) => i));
}
}
main() async {
// Create an StreamActor from a Handler that returns Stream.
final actor = StreamActor(StreamGenerator());
final stream = actor.send(2);
await for (final item in stream) {
print(item); // 0, 1
}
await actor.close();
}
ActorGroup #
ActorGroup
allows several Actor
instances to be grouped together, all based on the same Handler
implementation,
but executed according to one of the available strategies:
RoundRobin
- send message to a singleActor
, alternating which member of the group receives the message.MultiHandler
- send message tom
Actor
s, wait for at leastn
successful answers.
RoundRobing
is appropriate for cases where messages are CPU intensive to handle and there may be many of them.
MultiHandler
is a way to achieve high reliability by duplicating effort, as not all Actor
s in the group may
be healthy at all times. Having a few "backups" doing the same work on each message may be a good idea in case one or
more of the expected receivers are likely to fail, as the system will still continue to work without issues as long as
n
actors remain healthy... Also, by sending the same message to several actors, the message might be received in
different locations, making it much harder for it to be lost.
// create a group of 4 actors
final group = ActorGroup(Two(), size: 4);
print(await group.send(5)); // 10
group.close();
Messenger #
The Messenger
mixin is implemented by Actor
, ActorGroup
, and also LocalMessenger
, which runs its Handler
in the local Isolate
.
Messenger<int, int> messenger;
// a Messenger can be local
messenger = LocalMessenger(Two());
print(await messenger.send(2)); // 4
// or it can be an Actor
messenger = Actor(Two());
print(await messenger.send(3)); // 6
messenger.close();
// or an ActorGroup
messenger = ActorGroup(Two(), size: 2);
print(await messenger.send(4)); // 8
print(await messenger.send(5)); // 10
messenger.close();
This makes it possible to write code that works the same whether the message is handled locally or in another Isolate
.