A partial actor pattern with a global orchestrator.

Related tags

Utilities orchestra
Overview

orchestra

The orchestra pattern is a partial actor pattern, with a global orchestrator regarding relevant work items.

proc-macro

The proc macro provides a convenience generator with a builder pattern, where at it's core it creates and spawns a set of subsystems, which are purely declarative.

    #[orchestra(signal=SigSigSig, event=Event, gen=AllMessages, error=OrchestraError)]
    pub struct Opera {
        #[subsystem(MsgA, sends: [MsgB])]
        sub_a: AwesomeSubSysA,

        #[subsystem(MsgB, sends: [MsgA])]
        sub_b: AwesomeSubSysB,
    }
  • Each subsystem is annotated with #[subsystem(_)] where MsgA respectively MsgB are the messages being consumed by that particular subsystem. Each of those subsystems is required to implement the subsystem trait with the correct trait bounds. Commonly this is achieved by using #[subsystem] and #[contextbounds] macro.
    • #[contextbounds(Foo, error=Yikes, prefix=wherethetraitsat)] can applied to impl-blocks and fn-blocks. It will add additional trait bounds for the generic Context with Context: FooContextTrait for <Context as FooContextTrait>::Sender: FooSenderTrait besides a few more. Note that Foo here references the name of the subsystem as declared in #[orchestra(..)] macro.
    • #[subsystem(Foo, error=Yikes, prefix=wherethetraitsat)] is a extension to the above, implementing trait Subsystem<Context, Yikes>.
  • error= tells the orchestra to use the user provided error type, if not provided a builtin one is used. Note that this is the one error type used throughout all calls, so make sure it does impl From<E> for all other error types E that are relevant to your application.
  • event= declares an external event type, that injects certain events into the orchestra, without participating in the subsystem pattern.
  • signal= defines a signal type to be used for the orchestra. This is a shared "tick" or "clock" for all subsystems.
  • gen= defines a wrapping enum type that is used to wrap all messages that can be consumed by any subsystem.
    /// Execution context, always required.
    pub struct DummyCtx;

    /// Task spawner, always required
    /// and must implement `trait orchestra::Spawner`.
    pub struct DummySpawner;

    fn main() {
        let _orchestra = Opera::builder()
            .sub_a(AwesomeSubSysA::default())
            .sub_b(AwesomeSubSysB::default())
            .spawner(DummySpawner)
            .build();
    }

In the shown main, the orchestra is created by means of a generated, compile time erroring builder pattern.

The builder requires all subsystems, baggage fields (additional struct data) and spawner to be set via the according setter method before build method could even be called. Failure to do such an initialization will lead to a compile error. This is implemented by encoding each builder field in a set of so called state generics, meaning that each field can be either Init<T> or Missing<T>, so each setter translates a state from Missing to Init state for the specific struct field. Therefore, if you see a compile time error that blames about Missing where Init is expected it usually means that some subsystems or baggage fields were not set prior to the build call.

To exclude subsystems from such a check, one can set wip attribute on some subsystem that is not ready to be included in the Orchestra:

    #[orchestra(signal=SigSigSig, event=Event, gen=AllMessages, error=OrchestraError)]
    pub struct Opera {
        #[subsystem(MsgA, sends: MsgB)]
        sub_a: AwesomeSubSysA,

        #[subsystem(MsgB, sends: MsgA), wip]
        sub_b: AwesomeSubSysB, // This subsystem will not be required nor allowed to be set
    }

Baggage fields can be initialized more than one time, however, it is not true for subsystems: subsystems must be initialized only once (another compile time check) or be replaced by a special setter like method replace_<subsystem>.

A task spawner and subsystem context are required to be defined with Spawner and respectively SubsystemContext implemented.

Debugging

As always, debugging is notoriously annoying with bugged proc-macros.

Therefore expander is employed to yield better error messages. Enable with --feature=orchestra/expand.

License

Licensed under either of

at your option.

prioritized-metered-channel

Implements a metered variant of mpsc channels that provide an interface to extract metrics. The following metrics are available:

  • The amount of messages sent on a channel, in aggregate.
  • The amount of messages received on a channel, in aggregate.
  • How many times the caller blocked when sending messages on a channel.
  • Time of flight in micro seconds (us)
Comments
  • detect unconsumed/unsent messages, introduce generated dummy messages

    detect unconsumed/unsent messages, introduce generated dummy messages

    If a message type is never sent or never received, this leads to From<$ty> implementations being missing.

    The implementation here adds a check and throws and error pointint to the messages.

    Closes #13

    opened by drahnr 5
  • Crates.io ownership

    Crates.io ownership

    Hey @drahnr :wave:

    could you please

    cargo owner --add parity-crate-owner --add github:paritytech:core-devs
    

    for orchestra, orchestra-proc-macro and prioritized-metered-channel? :pray:

    Thank you in advance :)

    opened by ordian 5
  • expose feature dotgraph, use cargo workspace package

    expose feature dotgraph, use cargo workspace package

    Currently the graph feature is not exposed as part of crate orchestra.

    Proposed changeset:

    Rename the feature graph of orchestra-proc-macro to dotgraph and expose it via feature dotgraph in the public facing crate orchestra as well.

    opened by drahnr 0
  • Confusing error for unconsumed message

    Confusing error for unconsumed message

    #[orchestra(gen=AllMessages, ..)]
    struct X {
    #[subsystem(MsgA, sends: [Unconsumed])
    foo: Foo,
    #[subsystem(MsgB, sends: [Unconsumed])
    bar: Bar,
    }
    

    will raise an error about missing enum variant AllMessages::Unconsumed which is non-obvious how to resolve.

    Will be obsoleted once #11 is implemented, would possibly make sense to add a sense check to the proc-macro for the time being. CC @MathisWellmann

    opened by drahnr 0
  • broadcast_signal: parallelize sending and still use a timeout for completion

    broadcast_signal: parallelize sending and still use a timeout for completion

    If a subsystem is having a hard time and it's signal queue becomes full, all the subsequent subsystems will receive the signal much later on. We could have a timeout for completion of all futures, but this would still back pressure on the source of the signal. We could instead track individual timeouts for each send with a FuturesUnordered.

    For example, if in the below snippet of generated code sub2 blocks (up to timeout - 10s), then updates to sub3..6 will also be deleayed, leading to a general slowdown, as well as missing on some messages sent between unaffected systems and sub2 which can only be received after the signals are processed.

        /// Broadcast a signal to all subsystems.
        pub async fn broadcast_signal(
            &mut self,
            signal: OverseerSignal,
        ) -> ::std::result::Result<(), SubsystemError> {
            self.sub1.send_signal(signal.clone()).await?;
            self.sub2.send_signal(signal.clone()).await?;
            self.sub3.send_signal(signal.clone()).await?;
            self.sub4.send_signal(signal.clone()).await?;
            self.sub5.send_signal(signal.clone()).await?;
            self.sub6.send_signal(signal.clone()).await?;
    
            let _ = signal;
            Ok(())
        }
    
    enhancement 
    opened by sandreim 1
  • Avoid dependency on consumed message type, generate a marker type

    Avoid dependency on consumed message type, generate a marker type

    The generated code strongly relies on the consumed message type, which complicates the generated code significantly. Using a marker type and additional trait to annotate sent and consumed types, would likely be advantageous to reduce complexity and have one defining information anchor.

    opened by drahnr 0
  • attempt to get rid of `contextbounds`-proc-macro

    attempt to get rid of `contextbounds`-proc-macro

    since it's required to have the Context: SubsystemContext around to spawn a task, #[overseer::contextbounds(..)] was introduced. This could be avoided by allowing every Sender: ${Subsystem}SenderTrait to also implement a new trait SpawnTask or even trait SpawnNamed, since all that is required is sending a future to the overseer. Common practice for i.e. the job based subsystems and some subsystems. This could alleviate the need for that second proc-macro entirely and simplify the code based and improve compilation speed (hypothesis).

    opened by drahnr 0
  • move unbounded or bounded sends to declaration, rathern than impl locality by default

    move unbounded or bounded sends to declaration, rathern than impl locality by default

    Unify the sender API and only provide one API async fn send_message(msg: ..). bounded or unbounded is an impl detail that should be provided at the subsystem declaration, i.e.#[subsystem(DisputeDistributionMessage, sends: [ RuntimeApiMessage, DisputeCoordinatorMessage as unbounded, NetworkBridgeMessage,])] and thesend_messageimpl will take care of using the correct channels.ChannelsOutwill also contain less entries.

       #[subsystem(DisputeDistributionMessage, sends: [
                  RuntimeApiMessage,
                  DisputeCoordinatorMessage as unbounded,
                  NetworkBridgeMessage,
    ])]
    

    and the send_message impl will take care of using the correct channels. ChannelsOut will also contain less entries.

    opened by drahnr 0
  • Implement prioritized channels

    Implement prioritized channels

    Quoting from Polkadot issue https://github.com/paritytech/polkadot/issues/5517:

    Extend the metered::* types to have send::<Priority = Standard> generic argument which can either be Droppable, Low, Standard, High (not an enum!, all marker types).

    Pros:

    • allow a more nuanced handling of messages
    • keep the semantics simple

    Cons:

    • Complexity:
      • Will require more logic around sending
      • Requires multiple channels per subsystem
    opened by sandreim 0
Owner
Parity Technologies
Solutions for a trust-free world
Parity Technologies
wasm actor system based on lunatic

Wactor WASM actor system based on lunatic. Actors run on isolated green threads. They cannot share memory, and communicate only through input and outp

Noah Corona 25 Nov 8, 2022
Ector is an open source async, no-alloc actor framework for embedded devices

Ector is an open source async, no-alloc actor framework for embedded devices. Ector is an open source async, no-alloc actor framework for embedded dev

Drogue IoT 11 Dec 15, 2022
A partial reimplementation of pre-commit in Rust

preco A partial reimplementation of pre-commit in Rust. Important Heavily just a proof-of-concept and work-in-progress. There are bits that could prob

Aarni Koskela 8 Feb 22, 2024
A Rust macro for writing regex pattern matching.

regexm A Rust macro for writing regex pattern matching.

Takayuki Maeda 46 Oct 24, 2022
Propositional logic evaluator and rule-based pattern matcher

Plogic Propositional logic evaluator and pattern transformer written in Rust. Plogic evaluates logic expressions in a REPL (Read, Execute, Print, Loop

Jan 17 Nov 25, 2022
Node/Electron library for global key listening.

GlobalKey Building cargo install nj-cli nj-cli build --release Calling from node npm i globalkey # or yarn add globalkey const globalkey = require(

Will 20 Dec 15, 2022
✨ Safe, global singletons initialized at program start

✨ magic_static Safe, global singletons initialized at program start. Usage Simply add magic_static as a dependency in your Cargo.toml to get started:

William 5 Nov 8, 2022
The Polkadot Hackathon Global Series North America edition is the second in a series of hackathons that brings the cutting edge of blockchain to a global community.

Polkadot Hackathon Project We are translating Uniswap v2 to Ink. Dependencies Install cargo-contract for building Ink contracts: cargo install dylint-

Kristiyan Dilov 3 Jun 28, 2022
Northstar is a horizontally scalable and multi-tenant Kubernetes cluster provisioner and orchestrator

Northstar Northstar is a horizontally scalable and multi-tenant Kubernetes cluster provisioner and orchestrator. Explore the docs » View Demo · Report

Lucas Clerisse 1 Jan 22, 2022
Actor framework for Rust.

Actix Actor framework for Rust Documentation User Guide API Documentation API Documentation (master branch) Features Async and sync actors Actor commu

Actix 7.6k Jan 7, 2023
wasm actor system based on lunatic

Wactor WASM actor system based on lunatic. Actors run on isolated green threads. They cannot share memory, and communicate only through input and outp

Noah Corona 25 Nov 8, 2022
Pbot - pan93412's extensible userbot, which is full-documented, enginnered and based on Actor model.

pbot pan93412's extensible user bot, which is full-documented, engineered and based on Actor model. Usage Run cargo run --release [--features <modules

pan93412 4 Feb 28, 2022
Implementation of the RealWorld backend API spec in Actix, Rust's powerful actor system and most fun web framework.

Actix codebase containing real world examples (CRUD, auth, advanced patterns, etc) that adheres to the RealWorld spec and API. ❗ (2021/05/13) This cod

Allen 475 Jan 2, 2023
Ector is an open source async, no-alloc actor framework for embedded devices

Ector is an open source async, no-alloc actor framework for embedded devices. Ector is an open source async, no-alloc actor framework for embedded dev

Drogue IoT 11 Dec 15, 2022
A Platform-less, Runtime-less Actor Computing Model

CrossBus A Platform-Less, Runtime-Less Actor Computing Model Overview CrossBus is an implementation of Actor Computing Model, with the concept that Ru

Bruce Yuan 105 Apr 8, 2023
A small charting/visualization tool and partial vega implementation for Rust

Gust A charting library for rust! Disclaimer This is still very much a work in progress! APIs are very unstable and subject to change. Contributions a

Samuel Resendez 128 Dec 24, 2022
fastmod is a fast partial replacement for the codemod tool

fastmod is a fast partial replacement for codemod. Like codemod, it is a tool to assist you with large-scale codebase refactors, and it supports most of codemod's options.

Facebook Incubator 1.4k Dec 29, 2022
🦀️atos for linux by rust - A partial replacement for Apple's atos tool for converting addresses within a binary file to symbols.

atosl-rs ??️ atos for linux by rust - A partial replacement for Apple's atos tool for converting addresses within a binary file to symbols. tested on

everettjf 60 Dec 29, 2022
xcp is a (partial) clone of the Unix cp command. It is not intended as a full replacement

xcp is a (partial) clone of the Unix cp command. It is not intended as a full replacement, but as a companion utility with some more user-friendly feedback and some optimisations that make sense under certain tasks (see below).

Steve Smith 310 Jan 5, 2023
Automatically verify your [Partial]Eq/Ord invariants

Reltester Relation tester is a small testing utility for automatically checking the correctness of PartialEq, PartialOrd, Eq, and Ord implementations.

Filippo Neysofu Costa 18 Mar 24, 2023