{"id":28651848,"url":"https://github.com/Thomvanoorschot/backstage","last_synced_at":"2025-06-13T06:05:44.884Z","repository":{"id":278444749,"uuid":"932330571","full_name":"Thomvanoorschot/backstage","owner":"Thomvanoorschot","description":"This repository contains an experimental actor framework built using the Zig programming language. The framework implements actor-based concurrent programming patterns, including message passing between actors, actor lifecycle management, and state isolation. It leverages the libxev library for its event loop and concurrency.","archived":false,"fork":false,"pushed_at":"2025-06-12T20:58:27.000Z","size":17475,"stargazers_count":16,"open_issues_count":1,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-06-12T21:52:18.488Z","etag":null,"topics":["actor","actor-framework","libuv","libxev","zig-package","ziglang"],"latest_commit_sha":null,"homepage":"","language":"Zig","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/Thomvanoorschot.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,"zenodo":null}},"created_at":"2025-02-13T18:33:40.000Z","updated_at":"2025-06-12T20:58:30.000Z","dependencies_parsed_at":"2025-03-21T19:28:02.335Z","dependency_job_id":"f1b72994-b7e4-440a-8d50-a84ed6e5d5aa","html_url":"https://github.com/Thomvanoorschot/backstage","commit_stats":null,"previous_names":["thomvanoorschot/alphazig","thomvanoorschot/backstage"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/Thomvanoorschot/backstage","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Thomvanoorschot%2Fbackstage","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Thomvanoorschot%2Fbackstage/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Thomvanoorschot%2Fbackstage/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Thomvanoorschot%2Fbackstage/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Thomvanoorschot","download_url":"https://codeload.github.com/Thomvanoorschot/backstage/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Thomvanoorschot%2Fbackstage/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259592260,"owners_count":22881265,"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","actor-framework","libuv","libxev","zig-package","ziglang"],"created_at":"2025-06-13T06:01:39.609Z","updated_at":"2025-06-13T06:05:44.873Z","avatar_url":"https://github.com/Thomvanoorschot.png","language":"Zig","funding_links":[],"categories":["Zig","Systems Programming","\u003ca name=\"Zig\"\u003e\u003c/a\u003eZig"],"sub_categories":["Asynchronous Runtime"],"readme":"# Backstage: Actor Framework for Zig\n\nBackstage is a high-performance, event-driven actor framework for the Zig programming language. Built on top of [libxev](https://github.com/mitchellh/libxev), it provides a robust foundation for building concurrent applications using the actor model pattern.\n\nThe main goal of this project is to gain deeper understanding of the programming language while building something practical and useful. By implementing an actor framework from scratch, this project explores:\n\n- **Event-Driven Architecture**: Built on libxev for high-performance, non-blocking I/O operations\n- **Actor Lifecycle Management**: Automated actor supervision with parent-child relationships\n- **Memory Efficient**: Careful memory management with configurable inbox capacities\n- **Actor Registry**: Built-in registry for actor discovery and management\n- **Topic-based Messaging**: Publish/subscribe pattern with named topics for decoupled communication\n- **Concurrent programming patterns**: Built to be run on a single core yet handle concurrent workloads\n\n## Architecture\n\nThe framework consists of several core components:\n\n- **Engine**: The central runtime that manages the event loop and actor lifecycle\n- **ActorInterface**: Type-erased interface for actor communication and management\n- **Context**: Provides actors with access to the engine and manages parent-child relationships\n- **Registry**: Maps actor IDs and message types to actor instances\n- **Inbox**: Thread-safe message queue with configurable capacity\n- **Envelope**: Message wrapper that includes sender information and message types for routing\n- **Topic Subscriptions**: Decoupled publish/subscribe messaging system\n\n## Installation\n\nAdd Backstage to your `build.zig.zon`:\n\n```zig\n.dependencies = .{\n    .backstage = .{\n        .url = \"https://github.com/Thomvanoorschot/backstage/archive/main.tar.gz\",\n        .hash = \"...\", // Update with actual hash\n    },\n},\n```\n\nOr use zig fetch:\n\n```bash\nzig fetch --save https://github.com/Thomvanoorschot/backstage/archive/main.tar.gz\n```\n\n## Quick Start\n\n```zig\nconst std = @import(\"std\");\nconst backstage = @import(\"backstage\");\nconst Envelope = backstage.Envelope;\n\n// Define your actor\nconst MyActor = struct {\n    ctx: *backstage.Context,\n    allocator: std.mem.Allocator,\n\n    const Self = @This();\n    pub fn init(ctx: *backstage.Context, allocator: std.mem.Allocator) !*Self {\n        const self = try allocator.create(Self);\n        self.* = .{\n            .ctx = ctx,\n            .allocator = allocator,\n        };\n        return self;\n    }\n\n    pub fn receive(self: *Self(), envelope: Envelope) !void {\n        // This example shows zig-protobuf encoded payloads, any encoding (or none at all) would work\n        const actor_msg: MyActorMessage = try MyActorMessage.decode(message.payload, self.allocator);\n        if (actor_msg.message == null) {\n            return error.InvalidMessage;\n        }\n        switch (actor_msg.message.?) {\n            .init =\u003e |m| {\n                std.log.info(\"Received message {}\", .{m.example});\n            }\n        }\n    }\n\n    pub fn deinit(self: *Self) !void {\n        try self.ctx.shutdown();\n    }\n};\n\npub fn main() !void {\n    var gpa = std.heap.GeneralPurposeAllocator(.{}){};\n    defer _ = gpa.deinit();\n    const allocator = gpa.allocator();\n\n    // Initialize the engine\n    var engine = try backstage.Engine.init(allocator);\n    defer engine.deinit();\n\n    // Spawn actors\n    const publisher = try engine.spawnActor(MyActor, .{\n        .id = \"publisher\",\n        .capacity = 1024,\n    });\n\n    const subscriber = try engine.spawnActor(MyActor, .{\n        .id = \"subscriber\",\n        .capacity = 1024,\n    });\n\n    // Subscribe to the publisher's default topic\n    try subscriber.ctx.subscribeToActor(\"publisher\");\n\n    // Or subscribe to a specific topic\n    try subscriber.ctx.subscribeToActorTopic(\"publisher\", \"news\");\n\n    // Publish messages\n    // Normaly you would probably send some more complex encoded struct\n    try publisher.ctx.publish(\"Hello, subscribers!\");\n    try publisher.ctx.publishToTopic(\"news\", \"Breaking news!\");\n\n    // Send direct messages\n    try engine.send(null, \"subscriber\", .send, \"Direct message\");\n\n    // Run the event loop\n    try engine.run();\n}\n```\n\n### Publishing Messages\n\n```zig\n// Publish to the default topic\ntry actor.ctx.publish(\"Hello, world!\");\n\n// Publish to a specific topic\ntry actor.ctx.publishToTopic(\"events\", \"Something happened!\");\n```\n\n### Subscribing to Topics\n\n```zig\n// Subscribe to an actor's default topic\ntry subscriber.ctx.subscribeToActor(\"publisher-id\");\n\n// Subscribe to a specific topic from an actor\ntry subscriber.ctx.subscribeToActorTopic(\"publisher-id\", \"events\");\n\n// Unsubscribe from topics\ntry subscriber.ctx.unsubscribeFromActor(\"publisher-id\");\ntry subscriber.ctx.unsubscribeFromActorTopic(\"publisher-id\", \"events\");\n```\n\n### Message Handling\n\nActors receive both direct messages and published messages through the same `receive` method, differentiated by the `message_type` field in the envelope. You could add some logic based on this, but you don't have to:\n\n```zig\npub fn receive(self: *Self, envelope: Envelope) !void {\n    switch (envelope.message_type) {\n        .send =\u003e {\n            // Handle direct point-to-point messages\n        },\n        .publish =\u003e {\n            // Handle messages from subscribed topics\n        },\n        else =\u003e {},\n    }\n}\n```\n\n## Examples\n\nFor comprehensive examples and real-world usage, see the [Zigma algorithmic trading framework](https://github.com/Thomvanoorschot/zigma), which demonstrates advanced patterns.\n\n## API Reference\n\n### Engine\n\nThe `Engine` is the central component that manages the actor system:\n\n- `init(allocator)` - Initialize a new engine instance\n- `spawnActor(ActorType, options)` - Create and register a new actor\n- `send(sender, id, message_type, message)` - Send a message to a specific actor by ID\n- `run()` - Start the event loop\n- `deinit()` - Clean up resources\n\n### Context\n\nThe `Context` provides actors with communication and lifecycle management capabilities:\n\n#### Direct Messaging\n- `send(target_id, message)` - Send a direct message to another actor\n\n#### Topic-based Messaging\n- `publish(message)` - Publish a message to the default topic\n- `publishToTopic(topic, message)` - Publish a message to a specific topic\n- `subscribeToActor(target_id)` - Subscribe to another actor's default topic\n- `subscribeToActorTopic(target_id, topic)` - Subscribe to a specific topic from another actor\n- `unsubscribeFromActor(target_id)` - Unsubscribe from another actor's default topic\n- `unsubscribeFromActorTopic(target_id, topic)` - Unsubscribe from a specific topic\n\n#### Actor Management\n- `spawnActor(ActorType, options)` - Spawn a new actor\n- `spawnChildActor(ActorType, options)` - Spawn a child actor with supervision\n- `shutdown()` - Clean shutdown with automatic subscription cleanup\n\n### Actor Interface\n\nActors must implement:\n\n- `init(ctx, allocator)` - Actor initialization\n- `receive(envelope)` - Message handling for both direct and published messages\n- `deinit()` - Optional cleanup (automatically detected)\n\n### Envelope\n\nMessage wrapper containing:\n\n- `sender_id` - ID of the sending actor (optional)\n- `message_type` - Type of message (send, publish, subscribe, unsubscribe)\n- `message` - The actual message payload\n\n## Design Principles\n\n- **Isolation**: Actors maintain their own state and communicate only through messages\n- **Decoupling**: Topic-based messaging allows loose coupling between actors\n- **Supervision**: Parent actors manage child actor lifecycles\n- **Performance**: Zero-allocation message passing in steady state\n- **Type Safety**: Compile-time message type checking\n- **Resource Management**: Automatic cleanup of actor hierarchies and subscriptions\n\n## Current Status\n\nThis is an early-stage implementation, focusing on core actor framework concepts with topic-based messaging. The project is primarily meant as a learning exercise and may evolve significantly as understanding of both the language and actor patterns deepens.\n\n## License\n\nMIT License - see LICENSE file for details.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FThomvanoorschot%2Fbackstage","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FThomvanoorschot%2Fbackstage","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FThomvanoorschot%2Fbackstage/lists"}