-
Notifications
You must be signed in to change notification settings - Fork 22
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
Support closeConnectionTo
#25
Comments
From @netogallo on December 16, 2012 21:24 Hi, I am trying to get involved in the development of CH and thought about starting with this issue. I just wanted to ask if I understand the issue at a technical level: Each Node has an EndPoint (localEndPoint) and every time newLocalNode is called, a new endpoint is created for that node so there is one node for every endpoint (even though it is theoretically possible to have multiple nodes for a single endpoint using the createBareLocalNode function). So the issue consists of implementing a function closeConnectionsTo which given a node it should call the close function on all connections in the LocalNodeState? I know nodes and endpoints are different, but I don't find any place where endpoints and connections opened with the endpoint can be associated except the node to which the endpoint belongs. If some light could be shed here would be nice. Thank you |
From @edsko on December 17, 2012 8:29 No, |
From @hyperthunk on December 18, 2012 11:34 So @edsko it sounds like what we're asking for is a means of tracking all the connections associated with a specific I think the abstraction isn't too hard to get right. If you move the mechanism into the policy layer (i.e., Better still, move the API calls into the policy layer itself and parameterise them by the implementation itself. Say for example, that we have some type class (I know, I'm obsessed with these right!) that we can work with. Somewhere in type CreateTransportResult = Either (TransportError NewEndPointErrorCode) EndPoint
data TransportInternals a = TransportInternals a
class TransportProvider a where
createNew :: a -> TransportConfiguration -> IO CreateTransportResult
getInternals :: a -> Transport -> TransportInternals a
createTransport :: (TransportProvider a) => a -> TransportConfiguration -> IO CreateTransportResult
createTransport provider = createNew provider config
Now you can do something similar (with or without the type classes) so that the implementations have to provide some sort of data EndPoint = EndPoint {
provider :: EndPointProvider -- provides the callback functions
, address :: EndPointAddress
, connections :: MVar (StrictList Connection)
--- etc
}
connectEndpoint :: EndPoint -> Reliability -> ConnectHints -> IO (Either (TransportError ConnectErrorCode) Connection)
connectEndpoint ep r h = do
addr <- address ep
impl <- provider ep
-- let the backend do the real world
conn <- backendConnect impl addr r h
case conn of
Left _ -> return conn
Right cn -> appendSTM (connections ep) cn >> return conn
disconnectEndpoint :: EndPoint -> IO () --- probably want some return value but hey...
disconnectEndpoint ep = do
conns <- connections ep
foldrSTM conns closeConnection -- we can collect the outcomes here...
writeSTM conns newEmptyStrictList Anyway, that's just a sketch, but hopefully you see my point. By moving some of the mechanism into So gentlemen - how does that sound? Certainly it's a bigger refactoring than just implementing And if so, how do you feel about picking this up and making a start @netogallo? We'll step in and help as needed of course, as and when we're able to. |
From @edsko on December 18, 2012 11:43 No, I don't think that's the right way to go. You need to add
You are welcome to try and modify |
From @edsko on December 18, 2012 11:50 As regards getting the abstraction right -- you will need to talk to people involved with other kinds of transports. Is it realistic to demand something like |
From @hyperthunk on December 18, 2012 11:51
Hmn, good point, I hadn't thought about that. Clearly it's much better for
Well if your comment about just closing the socket is right then it doesn't sound too onerous. Where would you expect the API to live? On data EndPoint = EndPoint {
receive :: IO Event
--- snip
disconnectEndpoint :: IO () What is the different between It does sound like for TCP that |
From @hyperthunk on December 18, 2012 11:53
Yes indeed.
Just realised - you're closing the connections to the other endpoint but not closing the local end! |
From @edsko on December 18, 2012 11:58
Yes, this is not Note that that "in one go" is in serious need of expansion. How synchronous is this operation? What about data currently in the network? Etc. Etc. These are not easy questions to answer. |
From @netogallo on December 18, 2012 12:12 Implementing such function does seem to require careful consideration since users will be expecting somewhat homogeneous behavior in all transports which might be tricky. I will probably return to this issue once I have better understanding about transports, especially since I am not a networks guy. Thanks for the valuable feedback, I believe this discussion will be very useful to tackle the problem, but for the moment I will review CH a little more to figure out where my skills can be most useful. Thank you for the feedback. |
From @hyperthunk on December 18, 2012 13:41 @edsko - we deal with these kinds of problems every day at RabbitMQ and they are indeed very tricky to get right. In fact, I'd say I spend > 30% of my engineering efforts hardening the broker against situations that arise because of unreliable networks, and that's just considering TCP/IP. The problem with making this operation synchronous is that it can block for an arbitrary period of time, depending on the semantics of the underlying network/transport/protocol/etc. That's not good news when you're trying to shut down, upgrade, restart or whatever. One solution is timeouts, but then you're never sure just how long they should be and of course this should be a matter of policy. For connected protocols like TCP, using heartbeats is usually the right solution, with configurable parameters to control the frequency. Even for disconnected protocols this is usually a good idea. Making this operation asynchronous is fine, in theory, but there would need to be some kind of completion callback or result on which the caller can block if required. |
From @edsko on December 18, 2012 13:45 Yes, agreed on all the above. My main point is: don't rush into this one :) |
I believe it makes sense to include The term is An open connection is identified by a For every open connection, no
It may be enlightening to bring up issue #35. If that were implemented, then the absence of |
From @edsko on September 24, 2012 12:54
which closes the entire "bundle" of (outgoing and incoming) connections to another endpoint. Basically, "disconnect completely from this other endpoint" (a "heavyweight disconnect").
Once this is implemented we can resolve a TODO in
Control.Distributed.Process.Node
.Copied from original issue: haskell-distributed/distributed-process#37
The text was updated successfully, but these errors were encountered: