This is a research prototype. Please see the main GitHub page.
$ npm install async-actors
The library provide the following key features:
- A testing runtime that uses systematic concurrency testing to control all asynchrony and explore unexpected interleavings, exposing concurrency heisenbugs before release.
The library only provides messaging between actors within the same process; interprocess messaging must be handled by the developer.
The typed actors API enables developers to write actors using interfaces. Each actor has a FIFO queue of messages to handle; each message will be handled by the actor sequentially (one-after-the-other). When handling a message, an actor can create other actors and/or send messages to other actors and/or update its own state (i.e. its fields).
For example, in TypeScript:
// A file downloader actor that will be given a "goal"// (a list of files to download).
Each method of the interface is a message type that it can handle. We can implement the interface/actor to define how the messages will be handled:
We can create this actor and send it various messages:
// Create the actor and get a reference to it.;// These "method calls" actually just send a message to the actor.// The messages will be handled by the file downloader actor// at some point in the future.// The "method calls" return immediately,// regardless of whether the message has been handled yet.actorRef.sendUpdateGoal;actorRef.sendQueryLocalFSResult;
Notice that the methods all have a
void return type,
as they correspond to sending messages that will be processed
The API also supports synchronous-style messages using
For example, consider a file system actor:
// A file system actor that can query the file system.
We can send a
listFiles message and wait for the result
(just like a normal method call):
// Create the actor and get a reference to it.;;// Do something with files. E.g.;
Synchronous-style methods are those that do not start with "send"
must have a
Promise<...> return type.
Exceptions are also propagated.
Although these look like normal
async method calls,
the continuation (the execution state after an
is always executed/continued in the context of the calling actor
and other messages cannot be handled by the actor in the meantime
(although this behaviour can be changed via an option).
This unfortunately means that deadlock is possible
via a cyclic chain of calls.
The typed actors API is built on top of the simple actors API.
The simple actors API
enables developers to write more traditional, simple actors
by implementing the
// Define a union type of all messages we want to handle.;// Define a file downloader actor, similar to earlier.
Notice that, due to type narrowing,
the TypeScript compiler (and autocomplete tooling)
narrows the type of
msg within the if/else blocks.
Here is how we create the actor and send messages to it:
The testing runtime is implemented at the level of simple actors; testing of typed actors comes for free.
The library also supports thorough testing of different interleavings via the testing runtime. For example, the following TypeScript test harness aims to test what happens when a file is renamed at the same time as a file server actor tries to list the files in a directory:
The file server first obtains a list of files and then queries information about each file before returning the result. If the file is renamed between the list and query then an error will occur. This is very unlikely to happen when running normally. However, when using the testing runtime, the error is seen every time because all possible interleavings are explored.
See test.ts for the full test harness.
Please see the main GitHub page