celluloid / celluloid-io

UNMAINTAINED: See celluloid/celluloid#779 - Evented sockets for Celluloid actors
https://celluloid.io
MIT License
879 stars 93 forks source link

Server initiated socket.close for one connection terminates actor and all connections #106

Closed cognitiveflux closed 10 years ago

cognitiveflux commented 10 years ago

Repository with the bug example and potential proposed tests to validate when the issue is resolved:

https://github.com/cognitiveflux/celluloid-io-socket-close-error

Using EchoServer.rb as a trivial example, when calling socket.close on a specific connection, the Celluloid::IO actor will terminate even though other sockets are still open. As a result, all connections are closed.

This problem originally surfaced when tracing why a server-side socket closure, for connections exceeding a timeout threshold, was closing all connections.

tarcieri commented 10 years ago

The server is crashing with IOError, which is unhandled.

Try adding a rescue IOError here alongside EOFError:

https://github.com/celluloid/celluloid-io/blob/master/examples/echo_server.rb#L33

cognitiveflux commented 10 years ago

Adding the rescue IOError passes the tests and all the remaining connections stay open, but I'm curious why an IOError is raised in the first place. Writing an echo server using 'socket' and ruby threads doesn't raise an IOError when a socket connection is closed (only the client raises Errno::EPIPE, but nothing is raised on the server). Is this an issue coming from evented IO? Is there a better way to terminate the socket and associated fiber so that it doesn't raise?

tarcieri commented 10 years ago

EOFError, IOError, Errno::ECONNRESET, and Errno::EPIPE are all exceptions that indicate a socket error. You might notice the many different ways that socket closure is detected on e.g. IRC servers.

echo_server.rb should probably reflect this, however, what I've been wanting to make is a more high-level abstraction for developing network servers which wraps up these concerns.

The reason why there's a multitude of potential exceptions is because Celluloid::IO tries to be a low-level wrapper which doesn't abstract away these concerns, as opposed to something like EventMachine which is a high-level wrapper that forces a particular programming paradigm onto developers.

cognitiveflux commented 10 years ago

I'll close out the ticket then if it is executing as expected.

Were your thoughts on a higher level abstraction to create something similar to the level as EventMachine or EventMachine::WebSocket? Have you created a draft specification of what you're looking for from such an abstraction so that others could contribute towards the effort?

tarcieri commented 10 years ago

On Wed, May 14, 2014 at 9:54 AM, cognitiveflux notifications@github.comwrote:

Were your thoughts on a higher level abstraction to create something similar to the level as EventMachine or EventMachine::WebSocket?

With a completely different (synchronous) API, but perhaps similar ease of use

Have you created a draft specification of what you're looking for from such an abstraction so that others could contribute towards the effort?

I think the best approach would be an extraction from Reel (rewriting Reel on top of it at the same time), namely Reel::Server::HTTP (as Whatever::TCPServer), Reel::Server::SSL (as Whatever::SSLServer), and Reel::Connection (as Whatever::Connection)

Tony Arcieri