9 releases (4 breaking)
0.5.0 | Jul 10, 2024 |
---|---|
0.4.4 | Jun 25, 2024 |
0.4.0 | May 19, 2024 |
0.3.0 | May 19, 2024 |
0.1.0 | Feb 10, 2024 |
#472 in Asynchronous
Used in 4 crates
50KB
917 lines
Tokio GenServer
A simple Elixir/Erlang-GenServer-like actor implementation on Tokio.
Please see the documentation for information on usage and examples.
- Simple: Define 3 messages types and at least one callback, and you have an actor. No macro magic. No global "system"s or "pollution".
- Powerful: Initialization and exit callbacks. On completion, returns the actor itself, the whole running environment, and run result.
- Lightweight: Little code. No boxing except the ones introduced by Tokio.
- Blocking aCTOR (
Bctor
) for use with synchronous code.
NB: What is a GenServer? A Generic Server is a persistent process that handles messages sent to it. That's it. The message can either be a cast (fire-and-forget) or a call (request-response).
Major difference from Erlang
- Do not panic (crash). Return
anyhow::Error
instead. - Tokio scheduling is cooperative, not preemptive.
Your long-running async code should call
yield_now
in the middle so they can be interrupted. - Blanket supervision implementations are not very useful.
Instead, let your actors spawn children actors,
and let children send messages to their parents using
before_exit
to handle children exiting.
Alternatives
- 👍 Implements "proper" "process"; interfaces closer to Erlang.
- 👍 Type-erasure on "child", "pid".
- 👍 Supervisors.
- 👍 Multi-node.
- ❓ Catches unwind (also bad because of overhead?).
- ❓ Uses flume channels: may be faster, but more dependencies.
- 👎 Requires creating "applications" and "pollutes" the codebase.
- 👎 Call, cast, and reply message types are not distinguished.
- 👎 Uses magic global variables to manage "processes".
- 👎 No blocking.
- 👎 Requires messages to be serializable.
- 👎 Most traits are not object-safe.
Dependencies
~5–12MB
~130K SLoC