From 7cbbc151299f3311b46fd439ff7c00bd9a039750 Mon Sep 17 00:00:00 2001 From: Ari Seyhun Date: Sun, 6 Oct 2024 17:27:41 +0800 Subject: [PATCH] docs: update heading levels in book --- docs/core-concepts.mdx | 10 ++--- docs/core-concepts/actors.mdx | 10 ++--- docs/core-concepts/messages.mdx | 6 +-- docs/core-concepts/replies.mdx | 8 ++-- docs/core-concepts/requests.mdx | 8 ++-- docs/core-concepts/supervision.mdx | 10 ++--- docs/distributed-actors.mdx | 10 +++-- .../bootstrapping-actor-swarm.mdx | 10 +++-- .../dialing-connecting-nodes.mdx | 41 ++++++++++--------- .../messaging-remote-actors.mdx | 34 +++++++-------- .../registering-looking-up-actors.mdx | 12 +++--- docs/getting-started.mdx | 4 +- docs/index.mdx | 8 ++-- 13 files changed, 92 insertions(+), 79 deletions(-) diff --git a/docs/core-concepts.mdx b/docs/core-concepts.mdx index d6ae883..c278c74 100644 --- a/docs/core-concepts.mdx +++ b/docs/core-concepts.mdx @@ -4,22 +4,22 @@ title: Core Concepts Overview Welcome to the Core Concepts section of Kameo, where you'll find the foundational principles and components that make up the Kameo actor library. Understanding these concepts is crucial for effectively leveraging Kameo to build resilient, scalable, and concurrent applications. Below is an overview of the key concepts that form the backbone of Kameo's design and functionality. -### [  Actors](/core-concepts/actors) +## [  Actors](/core-concepts/actors) At the heart of Kameo lies the Actor model, a powerful abstraction that encapsulates state and behavior into independent, concurrent units. Actors are the primary building blocks of applications in Kameo, designed to isolate state and handle messages asynchronously. This isolation enhances fault tolerance and system resilience, as actors can fail and recover without affecting the overall system stability. -### [  Messages](/core-concepts/messages) +## [  Messages](/core-concepts/messages) Communication in Kameo is achieved through messages. Actors interact with each other exclusively by sending and receiving messages, ensuring a loose coupling between components. This messaging system underpins the asynchronous, non-blocking nature of Kameo, enabling efficient communication patterns and facilitating the development of responsive applications. -### [  Requests](/core-concepts/requests) +## [  Requests](/core-concepts/requests) Requests represent a specialized form of message exchange in Kameo, supporting both the "ask" and "tell" patterns. This library allows actors to either send messages without expecting a reply ("tell") or send messages and await responses ("ask"). The ask pattern, in particular, introduces a way to handle more complex interaction flows, including synchronous operations and error handling. -### [  Replies](/core-concepts/replies) +## [  Replies](/core-concepts/replies) Replies are responses to requests, completing the communication cycle between actors. By implementing the `Reply` trait, apps can define custom reply types, ensuring that actors can exchange meaningful data and status information. This mechanism is crucial for implementing robust and interactive systems where actors depend on the outcomes of their interactions. -### [  Supervision](/core-concepts/supervision) +## [  Supervision](/core-concepts/supervision) Supervision is a strategy for managing actor lifecycle and failure recovery, embodying the principle of "let it crash." In Kameo, actors can be linked together in supervision trees, allowing parent actors to monitor and respond to the failures of their children. This model provides a structured approach to error handling and recovery, ensuring system resilience and stability. diff --git a/docs/core-concepts/actors.mdx b/docs/core-concepts/actors.mdx index ec01fdb..a35eb2a 100644 --- a/docs/core-concepts/actors.mdx +++ b/docs/core-concepts/actors.mdx @@ -4,7 +4,7 @@ title: Actors Overview The core of Kameo is its actors. Actors are objects that encapsulate state and behavior. They interact with the rest of the system asynchronously, primarily through message passing, which allows for a high degree of concurrency and scalability. This section provides an overview of the `Actor` trait in Kameo, detailing its lifecycle, messaging, and supervision. -### Actor Trait Overview +## Actor Trait Overview The `Actor` trait defines the essential functionality and lifecycle hooks for an actor in Kameo. Implementing this trait allows you to create custom actors tailored to your application's requirements. Here are the key components of the `Actor` trait: @@ -13,7 +13,7 @@ The `Actor` trait defines the essential functionality and lifecycle hooks for an - **Messaging**: Actors communicate by sending messages to each other. When an actor is spawned, it returns an `ActorRef`, a reference to the actor that can be used to send messages to it. Messages are sent asynchronously and are processed sequentially by the receiving actor. - **Supervision**: Actors can supervise other actors, allowing for hierarchical error handling and recovery strategies. The `on_panic` and `on_link_died` hooks are integral to this, enabling actors to respond to failures in their child actors, as well as themselves. -#### **Deriving Actor** +### **Deriving Actor** To streamline the creation of actors and reduce repetitive boilerplate, Kameo offers a derive macro for the `Actor` trait. This macro not only simplifies the actor definition process but also provides sensible defaults that adhere to common practices. @@ -34,18 +34,18 @@ use kameo::Actor; struct MyActor { } ``` -### Lifecycle Management +## Lifecycle Management - **Starting**: The `on_start` hook is called before the actor starts processing messages. It's an opportunity to perform any necessary initialization. - **Stopping**: Actors are stopped either explicitly or when all references to their `ActorRef` are dropped. The `on_stop` hook allows for cleanup activities before the actor is fully stopped. - **Error Handling**: The `on_panic` hook is invoked when an actor panics or encounters an error while processing a message. This hook can decide whether the actor should be stopped or continue processing messages. - **Link Failures**: The `on_link_died` hook is called when a linked actor dies, providing a chance to react to the failure of closely related actors. -### Actor Creation and Messaging +## Actor Creation and Messaging Creating an actor involves implementing the `Actor` trait and then spawning the actor using `kameo::spawn`. Upon spawning, an `ActorRef` is returned, which is used to send messages to the actor. The actor processes messages using the `handle` method from the `Message` trait, optionally returning a reply. -#### Example Usage +### Example Usage ```rust struct MyActor; diff --git a/docs/core-concepts/messages.mdx b/docs/core-concepts/messages.mdx index e9b8aa0..db2399d 100644 --- a/docs/core-concepts/messages.mdx +++ b/docs/core-concepts/messages.mdx @@ -4,7 +4,7 @@ title: Messages Overview In Kameo, messages play a central role in the communication between actors. They are the primary means through which actors interact and modify each other's state. Understanding how messages work is fundamental to effectively using Kameo to build concurrent applications. -### **Defining Messages** +## **Defining Messages** Messages in Kameo are any static types that are handled by implementing the `Message` trait for an actor. This design allows for a wide variety of message types, from simple data structures to complex commands with associated data. The flexibility in message definition enables developers to design their actor system with clear and concise communication patterns. @@ -28,13 +28,13 @@ pub trait Message: Actor { - **Reply Type**: Each message has an associated `Reply` type, which is the type of the response that the message sender can expect to receive. This reply must implement the `Reply` trait, which ensures that it can be properly handled and sent back to the caller. - **Message Handler**: The core of the Message trait is the handle function. This function is where the logic for handling a specific message is defined. It takes mutable access to the actor (&mut self), the message itself (msg), and a context (ctx) that provides access to actor-specific functionality like sending messages to other actors or accessing the actor's state. The handle function returns a future that resolves to the message's reply type, allowing for asynchronous processing of messages. This design supports non-blocking message handling, which is essential for building responsive and scalable actor systems. -### Sequential Processing +## Sequential Processing Messages in Kameo are processed sequentially, one at a time, with exclusive mutable access to the actor's state. This sequential processing model simplifies state management within actors, as there is no need for explicit synchronization mechanisms like locks. When an actor is handling a message, it can safely modify its state without worrying about concurrent modifications from other messages. This model also ensures that messages are processed in the order they are received, which can be critical for maintaining consistency and correctness in certain applications. -### Asynchronous and Concurrent +## Asynchronous and Concurrent While messages are processed sequentially within a single actor, Kameo allows for concurrent processing across multiple actors. This is where the actor model shines, enabling high levels of concurrency without the complexity associated with traditional multithreading and synchronization. diff --git a/docs/core-concepts/replies.mdx b/docs/core-concepts/replies.mdx index 2a90cb2..6e1afaf 100644 --- a/docs/core-concepts/replies.mdx +++ b/docs/core-concepts/replies.mdx @@ -4,7 +4,7 @@ title: Replies Overview In Kameo, replies are the responses sent back from an actor following the receipt and processing of a message. These replies are fundamental to the ask pattern of actor communication, where a sender awaits a response to proceed. Ensuring that replies are properly structured and handled is crucial for maintaining the flow of information and control within your actor system. -### The Reply Trait +## The Reply Trait To facilitate communication within Kameo, all types intended to serve as responses from an actor must implement the `Reply` trait. This designation ensures that a type is recognized as a valid form of reply, capable of being processed within the actor's messaging system. @@ -12,11 +12,11 @@ Special attention is given to replies that encapsulate a `Result::Err` variant f While most standard library types already implement the `Reply` trait, there might be exceptions. Should you encounter a standard library type not implementing `Reply`, you are encouraged to report this through an issue. For types outside the standard library that do not implement `Reply`, a straightforward workaround is to wrap your reply type in a `Result`, where `T` is your original type. Given that any `Result` type inherently implements `Reply`, this approach often obviates the need for custom implementations of the `Reply` trait for your types, especially in scenarios where using `Result` types is a common practice. -### Deriving the Reply Trait +## Deriving the Reply Trait Kameo simplifies the implementation of the `Reply` trait through the `#[derive(Reply)]` macro. This macro automatically provides the necessary trait implementations for a type, making it straightforward to create custom reply types that integrate seamlessly with Kameo's messaging system. -#### Example Usage +### Example Usage ```rust use kameo::Reply; @@ -47,7 +47,7 @@ impl Message for MyActor { In this example, `MyReply` is defined as a struct with data relevant to the response expected by a sender. By deriving the `Reply` trait, `MyReply` is automatically equipped to serve as a response in Kameo's messaging system. This pattern allows for rich, structured data to be communicated back to senders, facilitating complex interactions and workflows within your actor system. -### Handling Replies +## Handling Replies When dealing with ask requests, it's important to handle replies gracefully. This involves not only receiving the reply but also managing potential timeouts and errors that might occur during the interaction. If the message handler returned an error while processing a message, it will be returned as a `SendError::HandlerError`. Kameo's design encourages clear, concise handling of these scenarios, ensuring that your actor system remains robust and resilient under various operational conditions. diff --git a/docs/core-concepts/requests.mdx b/docs/core-concepts/requests.mdx index 0cd574f..2461aaf 100644 --- a/docs/core-concepts/requests.mdx +++ b/docs/core-concepts/requests.mdx @@ -4,7 +4,7 @@ title: Requests Overview In the context of the Kameo, requests are the means through which actors communicate and interact with each other. These interactions are encapsulated in two primary forms: ask requests and tell requests. Understanding the nuances between these two types of requests is crucial for effectively managing actor behaviors and ensuring the robustness of your application. -### Ask Requests +## Ask Requests Ask requests are a form of message sending where the sender waits for a response from the receiver. This pattern is useful when the sender requires data or confirmation that an action has been completed before proceeding. Unlike tell requests, ask requests inherently support handling responses and errors, providing a direct way to deal with exceptional conditions. @@ -16,7 +16,7 @@ Key Features of Ask Requests: - **Mailbox Timeout**: For actors with a bounded mailbox, an optional `mailbox_timeout` can be specified. This timeout represents the maximum duration the request will wait in the queue before being processed. If the mailbox is full beyond this duration, the request may be dropped or an error returned. - **Reply Timeout**: A `reply_timeout` can also be set, indicating how long the sender will wait for a response. This is particularly useful for avoiding indefinite blocking in scenarios where the receiver might be unable to process the request promptly. -### Tell Requests +## Tell Requests Tell requests, on the other hand, are the "fire-and-forget" type of messages. When a tell request is sent, the sender does not wait for any acknowledgment or reply from the receiver. This approach is ideal for notifications or commands where the outcome does not directly influence the sender's immediate actions. @@ -26,7 +26,7 @@ Characteristics of Tell Requests: - **Error Handling**: Errors encountered by the actor while processing a tell request are treated as panics. By default, such panics may lead to the stopping of the actor, although this behavior can be customized via the `Actor::on_panic` hook to allow for error recovery or logging. - **Mailbox Timeout**: Similar to ask requests, a `mailbox_timeout` can be set for tell requests sent to actors with bounded mailboxes. This timeout helps manage the queuing behavior in scenarios where the actor's mailbox might be at capacity, ensuring that the system can gracefully handle backpressure. -### Request Methods +## Request Methods Sending a message can be done using one of the traits/methods listed in this table. Each cell describes the behaviour of the implementation depending on the mailbox type. @@ -48,7 +48,7 @@ The column headings describe the following: | `TryBlockingMessageSend` :: `try_blocking_send` | Tries to send a message, blocking the thread while waiting for a reply, but failing if the mailbox is full. | Tries to send a message, blocking the thread while waiting for a reply. | Tries to send a message, failing if the mailbox is full. | Sends a message. | | `ForwardMessageSend` :: `forward` | Sends a message, waiting for mailbox capacity with the reply being forwarded to a provided ReplySender. | Sends a message, with the reply being forwarded to a provided ReplySender. | ❌ | ❌ | -#### **Supported Requests** +### **Supported Requests** Depending on whether a message is being sent with a timeout set or to a remote actor, some methods may not be available. Below is table showing which methods are available under different circumstances. diff --git a/docs/core-concepts/supervision.mdx b/docs/core-concepts/supervision.mdx index 645e67c..b125143 100644 --- a/docs/core-concepts/supervision.mdx +++ b/docs/core-concepts/supervision.mdx @@ -4,28 +4,28 @@ title: Supervision Overview Supervision is a critical concept in building resilient actor systems, ensuring that the system can recover from failures and continue operating without interruption. In Kameo, supervision and actor lifecycle management are facilitated through a combination of customizable behavior hooks and actor linking. This page discusses how to effectively use these features to create robust actor hierarchies and manage actor failures gracefully. -### Customizing Actor Behavior on Panic +## Customizing Actor Behavior on Panic When an actor panics, its default behavior can be customized using the `on_panic` hook within the `Actor` trait. This hook allows developers to define custom logic that should execute when an actor encounters a panic, providing a first line of defense in managing unexpected failures. -### Linking Actors +## Linking Actors Beyond individual actor behavior, Kameo supports linking actors together to create a supervision tree. This structure enables actors to monitor each other's health and respond to failures, forming the backbone of a self-healing system. -#### Actor Links +### Actor Links Actors can be linked using two primary methods, which establish parent-child and sibling relationships: - `ActorRef::link_child` - `ActorRef::link_together` -#### Handling Link Failures +### Handling Link Failures When a linked actor dies, the surviving actors can react to this event using the `on_link_died` hook in the `Actor` trait. This hook provides the ID of the deceased actor and the reason for its termination, enabling the surviving actors to implement custom logic, such as restarting the failed actor or taking other remedial actions. The default behavior for `on_link_died` is to stop the current actor if the linked actor died for any reason other than a normal shutdown. This conservative default ensures that failures are not silently ignored, promoting system stability by preventing dependent actors from continuing in an inconsistent state. -#### Unlinking Actors +## Unlinking Actors In some scenarios, it may be necessary to remove links between actors, either to restructure the supervision tree or in response to changing application dynamics. Kameo provides methods for this purpose: diff --git a/docs/distributed-actors.mdx b/docs/distributed-actors.mdx index a5c4b8d..6456033 100644 --- a/docs/distributed-actors.mdx +++ b/docs/distributed-actors.mdx @@ -4,14 +4,14 @@ title: Distributed Actors Kameo’s distributed actor system enables actors to communicate seamlessly across different nodes in a decentralized network. This architecture provides a powerful foundation for building fault-tolerant, scalable, and resilient distributed systems. At its core, Kameo leverages [libp2p](https://libp2p.io) for peer-to-peer communication and a decentralized actor registry. -#### Key Components +## Key Components - **ActorSwarm**: The central structure responsible for managing peer-to-peer communication between nodes. It initializes the libp2p swarm, manages connections, and coordinates actor registration and message routing. - **RemoteActorRef**: A reference to an actor that resides on a remote node. This reference abstracts away the networking details and allows you to interact with remote actors using familiar APIs. - **Multiaddress**: libp2p uses multiaddresses to specify how nodes can be reached using different network protocols like TCP, WebSockets, or QUIC. Multiaddresses are essential for routing messages between nodes. - **Kademlia DHT**: Kameo uses Kademlia DHT to store and retrieve actor registration details. When an actor is registered, its name is stored as a key in the DHT, and the value contains information about how to reach the actor, making it discoverable by other nodes. -#### How Distributed Actors Work +## How Distributed Actors Work 1. **Bootstrapping the Actor Swarm**: Each node in the network must initialize an `ActorSwarm` to participate in the distributed system. The swarm manages the libp2p connections and allows the node to register actors and send/receive messages. @@ -19,7 +19,7 @@ Kameo’s distributed actor system enables actors to communicate seamlessly acro 3. **Remote Messaging**: Once an actor is registered, other nodes can look it up and send messages to it. The `RemoteActorRef` allows you to send and receive messages across the network without worrying about the underlying networking. -#### Why Use Distributed Actors? +## Why Use Distributed Actors? Distributed actors are ideal for building systems that need to scale horizontally across multiple machines or geographic locations. They enable fault-tolerant systems, as nodes can fail or be added without disrupting the overall network. Some common use cases for distributed actors include: @@ -27,13 +27,15 @@ Distributed actors are ideal for building systems that need to scale horizontall - **Microservices Architecture**: Building independent services that communicate via message passing, while maintaining resilience to failures. - **IoT Systems**: Distributed control systems where devices communicate with each other using lightweight actors. -#### Key Benefits +## Key Benefits - **Decentralized Architecture**: No single point of failure. Actors can be registered, discovered, and messaged from any node in the network. - **Fault Tolerance**: The system continues to operate even if nodes fail or become unreachable. Actor registration via Kademlia DHT ensures nodes can find each other. - **Scalability**: Add more nodes to the swarm to handle more actors and distribute load across the network. - **Flexible Networking**: By using libp2p, Kameo supports various network protocols, allowing it to adapt to different environments and infrastructure. +--- + #### What’s Next? Now that you have an understanding of how distributed actors work, you’re ready to dive deeper into the specifics of setting up the actor swarm, registering actors, and messaging across nodes. diff --git a/docs/distributed-actors/bootstrapping-actor-swarm.mdx b/docs/distributed-actors/bootstrapping-actor-swarm.mdx index 5fc54f1..bd54d81 100644 --- a/docs/distributed-actors/bootstrapping-actor-swarm.mdx +++ b/docs/distributed-actors/bootstrapping-actor-swarm.mdx @@ -4,7 +4,7 @@ title: Bootstrapping Actor Swarm Before actors can communicate across nodes in a distributed system, you need to initialize the `ActorSwarm`. The `ActorSwarm` is responsible for managing peer-to-peer connections, actor registration, and message routing across nodes. This section explains how to bootstrap the swarm, set up network listening, and prepare your system for distributed communication. -#### Initializing the Actor Swarm +## Initializing the Actor Swarm The first step in setting up distributed actors is bootstrapping the `ActorSwarm`. This initializes the swarm, allowing the node to participate in the network and accept incoming connections. @@ -14,7 +14,7 @@ let actor_swarm = ActorSwarm::bootstrap()?; This will initialize the swarm with default settings, preparing the node to listen for connections from other nodes. Once bootstrapped, you can register actors and send messages. -#### Bootstrapping with Identity +## Bootstrapping with Identity In some cases, you may want to bootstrap the swarm with a specific identity (keypair). This allows nodes to be uniquely identified in the network, which can be useful for secure communication or when interacting with known peers. @@ -25,7 +25,7 @@ let actor_swarm = ActorSwarm::bootstrap_with_identity(keypair)?; The `Keypair` generates a cryptographic identity for the node. This is useful for secure, verifiable communication between peers. The node will now be identified by its `PeerId`, derived from the keypair. -#### Listening on a Multiaddress +## Listening on a Multiaddress After bootstrapping the swarm, you need to instruct the node to listen on a specific network address. Kameo uses libp2p’s **multiaddress** format, which allows nodes to specify how they can be reached over the network. Multiaddresses define the protocol (e.g., TCP or QUIC) and the IP address/port combination. @@ -35,7 +35,7 @@ actor_swarm.listen_on("/ip4/0.0.0.0/udp/8020/quic-v1".parse()?).await?; In this example, the node is listening on the IP address `0.0.0.0` (which represents all available network interfaces) on UDP port `8020`, using the QUIC protocol. You can customize this address based on your network environment or use different protocols as needed. -#### Example: Bootstrapping and Listening +## Example: Bootstrapping and Listening Here’s a full example that combines bootstrapping the swarm and setting up a listener: @@ -55,6 +55,8 @@ async fn main() -> Result<(), Box> { Once the swarm is bootstrapped and listening, the node can register actors, dial other peers, and send messages. This setup ensures the node is part of the network and ready to accept and route messages. +--- + #### What’s Next? Now that your node is part of the distributed system, it’s time to explore how to connect to other nodes and establish communication. In the next section, we’ll cover how to dial and connect to peers using multiaddresses. diff --git a/docs/distributed-actors/dialing-connecting-nodes.mdx b/docs/distributed-actors/dialing-connecting-nodes.mdx index c091d91..2dceace 100644 --- a/docs/distributed-actors/dialing-connecting-nodes.mdx +++ b/docs/distributed-actors/dialing-connecting-nodes.mdx @@ -4,7 +4,7 @@ title: Dialing and Connecting to Other Nodes Once your node is bootstrapped and listening on an address, the next step in setting up a distributed actor system is dialing and connecting to other nodes. Kameo’s `ActorSwarm` allows nodes to discover and connect with peers using libp2p’s peer-to-peer communication capabilities. This section covers how to dial peers using multiaddresses, how to manage peer connections, and how libp2p’s mDNS feature can simplify peer discovery. -#### Dialing a Peer +## Dialing a Peer To establish a connection with another node, you need to dial its multiaddress. A multiaddress specifies the protocol, IP address, and port required to reach the node. @@ -14,7 +14,22 @@ actor_swarm.dial("/ip4/192.0.2.0/udp/8020/quic-v1".parse()?).await?; In this example, the node is dialing another node located at IP address `192.0.2.0` on UDP port `8020`, using the QUIC protocol. Once the connection is established, the node can interact with remote actors on the peer. -#### Auto-discovery with mDNS +### Dialing with Options + +For more advanced use cases, Kameo provides the `DialOpts` structure, which allows you to customize how you dial peers. This is useful when you need to include additional details or preferences when establishing connections, such as specifying peer IDs. + +```rust +let dial_opts = DialOpts::unknown_peer_id() + .address("/ip4/192.0.2.0/udp/8020/quic-v1".parse()?) + .build(); + +actor_swarm.dial(dial_opts).await?; +``` + +In this example, `DialOpts` is used to dial a peer at a known address without specifying the peer’s ID. This option can be customized depending on the situation, such as when connecting to peers with specific identities or conditions. + + +## Auto-discovery with mDNS In most cases, libp2p’s [**mDNS (Multicast DNS)**](https://docs.libp2p.io/concepts/discovery-routing/mdns/) feature allows nodes to automatically discover each other on the same local network, without needing to manually dial peers. This greatly simplifies setting up a distributed system, as peers will be able to find and connect to each other without explicit configuration. @@ -29,21 +44,7 @@ actor_swarm.listen_on("/ip4/0.0.0.0/udp/8020/quic-v1".parse()?).await?; This makes peer discovery effortless in environments where mDNS is available, such as local networks or development environments. -#### Dialing with Options - -For more advanced use cases, Kameo provides the `DialOpts` structure, which allows you to customize how you dial peers. This is useful when you need to include additional details or preferences when establishing connections, such as specifying peer IDs. - -```rust -let dial_opts = DialOpts::unknown_peer_id() - .address("/ip4/192.0.2.0/udp/8020/quic-v1".parse()?) - .build(); - -actor_swarm.dial(dial_opts).await?; -``` - -In this example, `DialOpts` is used to dial a peer at a known address without specifying the peer’s ID. This option can be customized depending on the situation, such as when connecting to peers with specific identities or conditions. - -#### Adding Peer Addresses Manually +## Adding Peer Addresses Manually In some cases, you may want to manually add a known peer’s address to the swarm without dialing immediately. This can be useful for preloading peers or when you want to manage connections programmatically. @@ -56,7 +57,7 @@ actor_swarm.add_peer_address(peer_id, addr); This example shows how to associate a peer’s identity with a known address. Once the peer address is added, the swarm will use it to attempt future connections or for message routing. -#### Disconnecting from Peers +## Disconnecting from Peers If you need to disconnect from a peer, you can do so using the peer’s `PeerId`. This is helpful when you want to manage peer connections and ensure that a node is no longer part of the active network. @@ -66,7 +67,7 @@ actor_swarm.disconnect_peer_id(peer_id); This cleanly terminates the connection with the specified peer, removing it from the swarm’s list of active peers. -#### Example: Dialing and Connecting to Peers +## Example: Dialing and Connecting to Peers Here’s a full example of how to dial a peer and establish a connection: @@ -89,6 +90,8 @@ async fn main() -> Result<(), Box> { This example shows how to bootstrap the swarm, set up a listener, and connect to another node using a multiaddress. +--- + #### What’s Next? Now that you can connect to other nodes, the next step is registering actors and looking them up across the network. This allows nodes to discover and interact with actors on remote peers. diff --git a/docs/distributed-actors/messaging-remote-actors.mdx b/docs/distributed-actors/messaging-remote-actors.mdx index 0663597..19810cf 100644 --- a/docs/distributed-actors/messaging-remote-actors.mdx +++ b/docs/distributed-actors/messaging-remote-actors.mdx @@ -4,7 +4,7 @@ title: Messaging Remote Actors Once actors are registered and discoverable across nodes, the next step is to start communicating with them. Kameo allows you to send messages to remote actors just like you would with local actors. The underlying networking is handled transparently, and messages are routed across the network using the `RemoteActorRef`. This section explains how to message remote actors and handle replies. -#### Sending Messages +## Sending Messages After looking up a remote actor using `RemoteActorRef`, you can send messages to it using the familiar `ask` and `tell` patterns. @@ -24,7 +24,7 @@ if let Some(actor) = remote_actor_ref { In this example, the node looks up the actor named `"my_actor"` and sends an `Inc` message to increment the actor's internal state. The message is serialized and sent over the network to the remote actor, and the reply is awaited asynchronously. -#### Fire-and-Forget Messaging +### Fire-and-Forget Messaging If you don’t need a response from the actor, you can use the `tell` method to send a message without waiting for a reply. @@ -35,7 +35,7 @@ actor.tell(&LogMessage { text: String::from("Logging event") }).send().await?; The `tell` method is useful for one-way communication where no acknowledgment is required, such as logging or notification systems. -#### Requirements for Remote Messaging +## Requirements for Remote Messaging There are two requirements to enable messaging between nodes: @@ -62,18 +62,7 @@ impl Message for MyActor { This `#[remote_message]` macro ensures that the message is properly serialized and routed to the correct actor across the network. The UUID string assigned to each message must be unique within the crate to avoid conflicts. -#### Handling Replies - -When sending a message using the `ask` pattern, you’ll typically want to handle a response from the remote actor. The reply type is specified in the actor’s message handler and can be awaited asynchronously. - -```rust -let result = actor.ask(&Inc { amount: 10 }).send().await?; -println!("Received reply: {}", result); -``` - -In this example, the reply from the remote actor is awaited, and the result is printed once received. - -#### Why the `#[remote_message]` Macro is Needed +### Why the `#[remote_message]` Macro is Needed Unlike actor systems that use a traditional enum for message types, Kameo allows actors to handle a variety of message types without defining a centralized enum for all possible messages. This flexibility introduces a challenge when deserializing incoming messages—because we don't know the exact message type at the time of deserialization. @@ -90,7 +79,18 @@ When a message is received, Kameo uses this hashmap to look up the appropriate f By using the `#[remote_message]` macro, Kameo registers each message type during link time, ensuring that when a message is received, the system knows how to deserialize it and which function to invoke on the target actor. -#### Example: Messaging a Remote Actor +## Handling Replies + +When sending a message using the `ask` pattern, you’ll typically want to handle a response from the remote actor. The reply type is specified in the actor’s message handler and can be awaited asynchronously. + +```rust +let result = actor.ask(&Inc { amount: 10 }).send().await?; +println!("Received reply: {}", result); +``` + +In this example, the reply from the remote actor is awaited, and the result is printed once received. + +## Example: Messaging a Remote Actor Here’s a full example of how to message a remote actor and handle its reply: @@ -118,6 +118,8 @@ async fn main() -> Result<(), Box> { In this example, a node is bootstrapped, connected to a network, and looks up a remote actor named `"my_actor"`. After finding the actor, the node sends an increment message (`Inc`) and waits for a response, which is printed upon receipt. +--- + #### What’s Next? Now that you’ve seen how to send messages to remote actors and handle replies, you can start building distributed systems where actors on different nodes communicate seamlessly. Experiment with sending different types of messages and handling remote interactions. diff --git a/docs/distributed-actors/registering-looking-up-actors.mdx b/docs/distributed-actors/registering-looking-up-actors.mdx index 38b8132..23561fb 100644 --- a/docs/distributed-actors/registering-looking-up-actors.mdx +++ b/docs/distributed-actors/registering-looking-up-actors.mdx @@ -4,7 +4,7 @@ title: Registering and Looking up Actors In a distributed system, actors need to be discoverable by other nodes so that they can receive messages from remote peers. Kameo provides actor registration and lookup mechanisms using a decentralized registry powered by **Kademlia DHT** (Distributed Hash Table). This section covers how to register actors and look them up across the network using `ActorSwarm`. -#### Registering Actors +## Registering Actors After bootstrapping the `ActorSwarm` and setting up the node to listen for connections, actors can be registered under unique names. This makes them discoverable by other nodes, allowing remote actors to send messages to them. @@ -18,7 +18,7 @@ actor_ref.register("my_actor").await?; In this example, an actor of type `MyActor` is spawned and registered with the name `"my_actor"`. The name is propagated across the network using the Kademlia DHT, which stores the mapping between the actor’s name and its reference on the node. Other nodes can now look up and interact with this actor using its registered name. -#### Actor Lookup +## Actor Lookup Once an actor is registered, other nodes can look it up by name. The `RemoteActorRef::lookup` method allows you to retrieve a reference to an actor that is registered on a remote node. If the lookup is successful, the returned `RemoteActorRef` can be used to send messages to the remote actor, just like with local actors. @@ -37,7 +37,7 @@ if let Some(actor) = remote_actor_ref { In this example, the node attempts to look up an actor registered with the name `"my_actor"`. If the actor is found on a remote node, a `RemoteActorRef` is returned, allowing the local node to send messages to the remote actor. A `RemoteActorRef` may in fact be a reference to an actor running on the current node. -#### Kademlia DHT: Decentralized Actor Lookup +## Kademlia DHT: Decentralized Actor Lookup Kameo’s actor registration and lookup system is powered by **Kademlia DHT**, a distributed hash table used to store and retrieve actor registration details across nodes. When an actor is registered, its name is stored as a key in the DHT, and the value is a reference to the actor on the node where it was registered. @@ -46,7 +46,7 @@ This decentralized registry ensures that actors can be discovered efficiently ac - **Registration**: When an actor is registered, its name is propagated to other nodes using the DHT. - **Lookup**: When a node looks up an actor by name, the DHT retrieves the location of the actor from the network and returns a reference to the actor. -#### Example: Registering and Looking up Actors +## Example: Registering and Looking up Actors Here’s a full example showing how to register an actor on one node and look it up from another: @@ -74,7 +74,7 @@ async fn main() -> Result<(), Box> { In this example, Node 1 registers an actor with the name `"my_actor"`, and Node 2 looks up the actor using its registered name. Once the actor is found, Node 2 sends a message to it. -#### Retry Mechanism for Actor Lookup +## Retry Mechanism for Actor Lookup In distributed systems, there can be cases where an actor is not yet registered or its registration hasn’t fully propagated through the Kademlia DHT. This can happen if the actor has just been registered or if the network is still syncing. In such cases, it’s useful to implement a retry mechanism when looking up actors, giving the system time to propagate the registration. @@ -101,6 +101,8 @@ In this example, the lookup is retried up to 5 times, with a 2-second delay betw A cleaner solution might involve using a crate such as [backon](https://crates.io/crates/backon) for retrying actor lookups. +--- + #### What’s Next? With actors now registered and discoverable across nodes, the next step is to explore how to send messages to remote actors. The messaging system allows you to send and receive messages between actors on different nodes using `RemoteActorRef`. diff --git a/docs/getting-started.mdx b/docs/getting-started.mdx index 6121a3c..dbb2649 100644 --- a/docs/getting-started.mdx +++ b/docs/getting-started.mdx @@ -80,7 +80,9 @@ async fn main() -> Result<(), Box> { // Use a Result retu - **Spawning and Messaging**: The `spawn` function creates an instance of the `HelloWorldActor` and returns a reference to it (`actor_ref`). The `tell` method is then used to send a `Greet` message to the actor. The `send` method is awaited to ensure the message is sent to the actors mailbox. - **Asynchronous Runtime**: The example uses Tokio as the asynchronous runtime, indicated by the `#[tokio::main]` attribute. This is necessary for running asynchronous Rust code. -### Next Steps +--- + +#### Next Steps This example is a starting point for building applications with Kameo. From here, you can explore more complex actor behaviors, state management, actor supervision, and building distributed systems with remote actors. diff --git a/docs/index.mdx b/docs/index.mdx index c0b2f4e..11ea408 100644 --- a/docs/index.mdx +++ b/docs/index.mdx @@ -5,18 +5,18 @@ image: https://github.com/tqwewe/kameo/blob/main/banner.png?raw=true Embarking on the journey of building software, you're often faced with the challenge of managing complexity, ensuring reliability, and achieving scalability. That's where Kameo steps in—a powerful, yet approachable, actor framework built on Tokio, a proven runtime in the Rust ecosystem renowned for its amazing capabilities for asynchronous and concurrent code. Kameo is designed to help you conquer these challenges head-on, offering a simplified approach to building robust applications. -###   Simplifying Concurrency +##   Simplifying Concurrency At its core, Kameo simplifies the daunting world of concurrent programming. With its actor-based model, it abstracts away the nitty-gritty details of thread management, locking, and synchronization. Instead, you get to focus on what truly matters: designing your system's logic. By encapsulating state and behavior within actors that communicate through messages, Kameo enables you to build systems that are naturally concurrent and resilient. -###   Building Resilient Systems +##   Building Resilient Systems Reliability is non-negotiable in today's software landscape. Kameo is built with this principle in mind, offering robust supervision strategies that allow your system to recover from failures gracefully. Instead of painstakingly handling every possible error scenario, you can design your system to "let it crash" and rely on Kameo to manage the recovery process, keeping your application running smoothly and reliably. -###   Scalability Made Easy +##   Scalability Made Easy Whether you're developing a small utility or a large-scale distributed system, scalability is key. Kameo's lightweight actor model and efficient message-passing mechanisms make it inherently scalable. Your application can grow from handling dozens to millions of concurrent operations with minimal changes to the underlying architecture. -###   Why Kameo? +##   Why Kameo? In a world where complexity is the norm, Kameo stands out by offering simplicity, resilience, and scalability. It's not just about making concurrent programming easier—it's about empowering you to build the reliable, efficient, and scalable systems that today's users demand. Whether you're a seasoned developer or just starting out, Kameo is designed to be relatable and accessible, providing you with the tools you need to bring your ideas to life.