Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Agents without Output/callback #307

Closed
hgzimmerman opened this issue Jul 1, 2018 · 5 comments
Closed

Agents without Output/callback #307

hgzimmerman opened this issue Jul 1, 2018 · 5 comments

Comments

@hgzimmerman
Copy link
Member

hgzimmerman commented Jul 1, 2018

Description

I'm submitting a Feature Request

For the Router I'm writing, I'm trying to make it as ergonomic as possible. One of the Issues I have, is that in some situations, I construct an Agent that will never have its callback called; I only want to send messages to it. Having to create a bridge using a callback that will never be called could be confusing to someone using the router.

I think this would best be dealt with by creating an analogue to Agent that doesn't have an Output associated type and can have a Bridge analogue constructed without a callback.
This way, messages could be sent from a Component to an Agent-like struct which will send its own message to another Actor, without having to own the Agent. I would like a way to have my_boxed_agent_bridge.send(MyMsg::Variant) effectively instantiate the MyAgent if it doesn't exist yet, and then call a MyAgent::handle(&mut self, MyMsg::Variant), which could then pass the message along.

@kellytk
Copy link
Contributor

kellytk commented Sep 14, 2019

It should be optional for components using an agent to receive messages from it. Components which only send messages to an agent but have no reason to receive messages from it shouldn't be required to clutter update, as is currently the case.

@hgzimmerman
Copy link
Member Author

hgzimmerman commented Sep 14, 2019

Mostly ignoring the implementation suggestions of the OP, it might be better to attack this problem from the Bridges. All this is seeking to do is allow bridges to be created without a callback, hence allowing you to send messages, but not receive them.


We currently have this:

impl<T> Bridged for T where T: Agent {
    fn bridge(callback: Callback<Self::Output>) -> Box<dyn Bridge<Self>> {
        Self::Reach::spawn_or_join(callback)
    }
}

pub trait Discoverer {
    fn spawn_or_join<AGN: Agent>(_callback: Callback<AGN::Output>) -> Box<dyn Bridge<AGN>>{...}
}

pub trait Bridge<AGN: Agent> {
    /// Send a message to an agent.
    fn send(&mut self, msg: AGN::Input);
}

What we wan't to see is:

impl<T> Bridged for T where T: Agent {
    fn bridge(callback: Callback<Self::Output>) -> Box<dyn Bridge<Self>> {
        Self::Reach::spawn_or_join(callback)
    }
    fn bridge_with_no_response() -> Box<dyn Bridge<Self>> {
        Self::Reach::spawn_or_join_without_callback()
    }
}

pub trait Discoverer {
    fn spawn_or_join<AGN: Agent>(_callback: Callback<AGN::Output>) -> Box<dyn Bridge<AGN>>{...}
    fn spawn_or_join_without_callback<AGN: Agent>() -> Box<dyn Bridge<AGN>>{...}
}

// Bridge remains the same.

The actual implementations of Discoverer end up working with an AgentScope, which is a wrapper around Shared<AgentRunnable<AGN>>.

Lets drill down into the Context Bridge:
It works using a pool of LocalAgents.
When a bridge is created, create_bridge(callback) is called on the local agent. This creates an id so responses can be routed later to the appropriate bridge. Since we won't want that, we can eliminate that in a sister-method.
Ultimately, a ContextBridge is created like so:

        ContextBridge {
            scope: self.scope.clone(),
            id: id.into(),
        }

If this can be changed to be like:

        ContextBridge {
            scope: self.scope.clone(),
            id: Some(id.into()),
        }

With an optional Id, we can have the sister bridge method look like:

    fn create_no_callback_bridge(&self) -> ContextBridge<AGN> {
        ContextBridge {
            scope: self.scope.clone(),
            id: None
        }
}

A bunch of associated code would have to change a little to handle the case where context bridges may not have an Id, but this is the place to start when adding support for agents to have no-callback bridges.

@hgzimmerman
Copy link
Member Author

This change doesn't make sense for Job, because without a response, you would just be sending messages into the void. Public looks to be about the same as Context and Global seems to be not really implemented in the first place.

@hgzimmerman
Copy link
Member Author

For the Job case, you should probably override the 'without callbacks' bridge fn with a panic explaining that calling it would never make sense.

@hgzimmerman
Copy link
Member Author

As @kellytk suggested in the gitter, dispatch() or dispatcher() would be more terse alternatives to the bridge_with_no_response() suggested above.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants