{"id":13550092,"url":"https://github.com/LeonHartley/Coerce-rs","last_synced_at":"2025-04-02T23:31:49.296Z","repository":{"id":39619737,"uuid":"225160577","full_name":"LeonHartley/Coerce-rs","owner":"LeonHartley","description":"Actor runtime and distributed systems framework for Rust","archived":false,"fork":false,"pushed_at":"2024-05-02T11:50:56.000Z","size":1778,"stargazers_count":718,"open_issues_count":17,"forks_count":27,"subscribers_count":15,"default_branch":"master","last_synced_at":"2025-03-04T13:06:04.263Z","etag":null,"topics":["actor-model","actors","async","async-await","asynchronous","await","cluster","distributed","distributed-systems","event-driven","event-driven-architecture","remote","rust","scalable","sharded","sharded-cluster","tokio","tokio-rs"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/LeonHartley.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-12-01T12:49:58.000Z","updated_at":"2025-02-18T20:05:39.000Z","dependencies_parsed_at":"2024-08-01T12:17:53.440Z","dependency_job_id":"795a48fb-2d0b-4e26-ab1b-f9f38f28bbb3","html_url":"https://github.com/LeonHartley/Coerce-rs","commit_stats":{"total_commits":361,"total_committers":5,"mean_commits":72.2,"dds":0.5096952908587258,"last_synced_commit":"78f0490486495cba47cceeabfcb213bf6767fd84"},"previous_names":[],"tags_count":32,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LeonHartley%2FCoerce-rs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LeonHartley%2FCoerce-rs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LeonHartley%2FCoerce-rs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LeonHartley%2FCoerce-rs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/LeonHartley","download_url":"https://codeload.github.com/LeonHartley/Coerce-rs/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246911128,"owners_count":20853653,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["actor-model","actors","async","async-await","asynchronous","await","cluster","distributed","distributed-systems","event-driven","event-driven-architecture","remote","rust","scalable","sharded","sharded-cluster","tokio","tokio-rs"],"created_at":"2024-08-01T12:01:28.864Z","updated_at":"2025-04-02T23:31:48.036Z","avatar_url":"https://github.com/LeonHartley.png","language":"Rust","funding_links":[],"categories":["Rust"],"sub_categories":[],"readme":"# Coerce-rs  ![coerce-rs](https://github.com/LeonHartley/Coerce-rs/workflows/coerce-rs%20tests/badge.svg)\n\nCoerce-rs is an asynchronous (async/await) Actor runtime and distributed system framework for Rust. It allows for\nextremely simple yet powerful actor-based distributed system development. With minimal code, you can build a highly\nscalable, fault-tolerant modern actor-driven application.\n\n## Crates\n| **Crate**                                               | **Purpose**                                                                                                                           | **Latest Version**                                              |\n|---------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------|\n| [coerce](https://crates.io/crates/coerce)               | The main Coerce runtime and framework                                                                                                 | ![crates.io](https://img.shields.io/crates/v/coerce.svg)        |\n| [coerce-redis](https://crates.io/crates/coerce-redis)   | Actor persistence provider for Redis. Enables event source and snapshots to be read and written from Redis.                           | ![crates.io](https://img.shields.io/crates/v/coerce-redis.svg)  |\n| [coerce-macros](https://crates.io/crates/coerce-macros) | Useful macros allowing for quick implementations of snapshots, JSON-serialisable remote messages and more.                            | ![crates.io](https://img.shields.io/crates/v/coerce-macros.svg) |\n| [coerce-k8s](https://crates.io/crates/coerce-k8s)       | Kubernetes discovery provider, automatically discover cluster peers hosted in Kubernetes, based on a configurable pod-selection label | ![crates.io](https://img.shields.io/crates/v/coerce-k8s.svg)    |\n\n# Using Coerce in your own project\nFirst step to using Coerce in your project is to add the coerce crate dependency, this can be done by adding the following\nto your Cargo.toml:\n\n```toml\n[dependencies]\ncoerce = { version = \"0.8\", features = [\"full\"] }\n```\n\n#### Optional: enabling `tracing/valuable`\nCoerce provides support for `tracing/valuable`, which can be used for enriching logs with information on the actor context. This is currently an unstable feature, which can be enabled by adding the `coerce/tracing-unstable` feature and the following section to your `.cargo/config.toml` file:\n```\n[build]\nrustflags = [\"--cfg\", \"tracing_unstable\"]\n```\n\nNote: if your project already depends on `tracing` crate, you'll need to enable the `valuable` feature too!\n\n## Features\n\n### Actors\n - Type-safe actors\n - Supervision / child spawning\n - Location-transparent `ActorRef\u003cA\u003e` types (ActorRef may comprise of a `LocalActorRef\u003cA\u003e` or a `RemoteActorRef\u003cA\u003e`)\n - Metrics available out of the box\n\n## Remoting\n  - Communicate with an actor from anywhere in the cluster\n  - Actors can be deployed locally or to other remote nodes\n  - Protobuf network protocol\n  - Actor-driven networking layer\n\n### Distributed Sharding\n\n- Actor IDs can resolve to specific shards, which can be spread across a cluster of Coerce nodes\n- Automatic load balancing, shards will be fairly allocated across the cluster\n- Self-recovering when nodes are lost, actors can be automatically restarted on other healthy nodes\n\n### Persistence\n\n- Journaling / event sourcing\n- Snapshotting\n- Pluggable storage providers (in-memory and redis readily available, MySQL is planned)\n\n### Distributed PubSub\n\n- Actors can subscribe to programmable topics from anywhere in the cluster\n- System-level topic provided to receive updated system state (e.g new nodes joining, nodes lost etc.)\n\n### HTTP API\n\n- Easily accessible metrics and information useful for diagnosis\n\n\n# Building and testing the Coerce libraries\nBuilding Coerce is easy. All you need is the latest Rust stable or nightly installed, along with Cargo.\n\n```shell\n# Clone the repository\ngit clone https://github.com/leonhartley/coerce-rs \u0026\u0026 cd coerce-rs\n\n## run Cargo build to build the entire workspace, including the examples and the tests\ncargo build\n\n## Alternatively, if you'd like to build the library, dependencies and run the tests\ncargo test --all-features\n```\n\n# How to run the examples\n### Sharded Chat example\n\n\n# ActorSystem\n\nEvery actor belongs to an ActorSystem.\n\n### async/await Actors\n\nAn actor is just another word for a unit of computation. It can have mutable state, it can receive messages and perform\nactions. One caveat though.. It can only do one thing at a time. This can be useful because it can alleviate the need\nfor thread synchronisation, usually achieved by locking (using `Mutex`, `RwLock` etc).\n\n\n\n#### How is this achieved in Coerce?\n\nCoerce uses Tokio's MPSC channels ([tokio::sync::mpsc::channel][channel]), every actor created spawns a task listening\nto messages from a\n`Receiver`, handling and awaiting the result of the message. Every reference (`ActorRef\u003cA: Actor\u003e`) holds\na `Sender\u003cM\u003e where A: Handler\u003cM\u003e`, which can be cloned.\n\nActors can be stopped and actor references can be retrieved by ID from anywhere in your application. IDs are `String`\nbut if an ID isn't provided upon creation, a new `Uuid` will be generated. Anonymous actors are automatically dropped (\nand `Stopped`)\nwhen all references are dropped. Tracked actors (using global fn `new_actor`) must be stopped.\n\n\u003cdetails\u003e\n  \u003csummary\u003eBasic ActorSystem + EchoActor example\u003c/summary\u003e\n\n### Example\n\n```rust\npub struct EchoActor {}\n\n#[async_trait]\nimpl Actor for EchoActor {}\n\npub struct EchoMessage(String);\n\nimpl Message for EchoMessage {\n    type Result = String;\n}\n\n#[async_trait]\nimpl Handler\u003cEchoMessage\u003e for EchoActor {\n    async fn handle(\n        \u0026mut self,\n        message: EchoMessage,\n        _ctx: \u0026mut ActorContext,\n    ) -\u003e String {\n        message.0.clone()\n    }\n}\n\npub async fn run() {\n    let mut actor = new_actor(EchoActor {}).await.unwrap();\n\n    let hello_world = \"hello, world\".to_string();\n    let result = actor.send(EchoMessage(hello_world.clone())).await;\n\n    assert_eq!(result, Ok(hello_world));\n}\n```\n\n### Timer Example\n\n```rust\npub struct EchoActor {}\n\n#[async_trait]\nimpl Actor for EchoActor {}\n\npub struct EchoMessage(String);\n\nimpl Message for EchoMessage {\n    type Result = String;\n}\n\npub struct PrintTimer(String);\n\nimpl TimerTick for PrintTimer {}\n\n#[async_trait]\nimpl Handler\u003cPrintTimer\u003e for EchoActor {\n    async fn handle(\u0026mut self, msg: PrintTimer, _ctx: \u0026mut ActorContext) {\n        println!(\"{}\", msg.0);\n    }\n}\n\npub async fn run() {\n    let mut actor = new_actor(EchoActor {}).await.unwrap();\n    let hello_world = \"hello world!\".to_string();\n\n    // print \"hello world!\" every 5 seconds\n    let timer = Timer::start(actor.clone(), Duration::from_secs(5), TimerTick(hello_world));\n\n    // timer is stopped when handle is out of scope or can be stopped manually by calling `.stop()`\n    sleep(Duration::from_secs(20)).await;\n    timer.stop();\n}\n```\n\n\u003c/details\u003e\n\n\n[channel]: https://docs.rs/tokio/0.2.4/tokio/sync/mpsc/fn.channel.html\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FLeonHartley%2FCoerce-rs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FLeonHartley%2FCoerce-rs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FLeonHartley%2FCoerce-rs/lists"}