erlang-redis
erlang-redis copied to clipboard
redis:connect() crashes on db unavailability
Maybe I'm missing something, but it seems to me that if I run redis:connect() when the redis db is down, the client process crashes (i.e. some linked process seems to send an exit signal from redis_client:init/1). This can't be caught with try/catch and the only way seems to be trapexit. This seems weird because the success case return value is {ok, Connection} which would make me expect the error return to be {error, Something}.
Am I making some dumb error? Is there a less drastic way to handle the situation? I'm not that fluent in Erlang so I could be overlooking something.
I opened an Erlang-questions thread starting here:
http://erlang.org/pipermail/erlang-questions/2013-June/074093.html
and a couple people suggested that connection failure should return an error code instead of craashing.
Thanks.
The last few changes should address this. The new behavior of redis:connect is to not link, which will give you an error result. If you want to start and link to the client, use the new redis:connect_link functions.
Take a look at examples/dbservice for a process (gen_server) that specializes in maintaining connections to a client connection and exposes some application level functions. This might be a good model for something in your application.
Thinking about this a little more, gen_server:start() doesn't seem like generically the right thing either, since it can leak connections if the client process exits/crashes. That was probably the reason for using start_link in the first place. Maybe the library should monitor the client instead of linking to it, and exit if the client exits? It's probably not too much of an issue for my app, which holds a long term connection in a single process, but just wondering what the best way to do this is.
I see there is also some mention of connection pooling. If the connections are passed around to different processes that might use them, maybe even start_link doesn't deal with leaks, and the connections have to be gc'd somehow. I was a little surprised to find that the connections are processes rather than ports. I'm guessing the reason is to be able to communicate with them from multiple clients.
Does this make sense?
The idea behind start (as opposed to start_link) is that the caller can setup a link or monitor or nothing, depending on requirements. We don't want to do anything in particular in this case. E.g. look at the dbservice example -- it uses redis:connect/0 (no link) but then links to the process shortly thereafter.
The connections have to be processes -- otherwise your application would be responsible for dealing with IO to/from the server. Ports are just an abstraction for dealing with external resources.
On Fri, Jun 7, 2013 at 3:06 PM, paul-mhq [email protected] wrote:
Thinking about this a little more, gen_server:start() isn't generically the right thing either, since it can leak connections if the client process exits. That was probably the reason for using start_link in the first place. Maybe the library should monitor the client instead of linking to it, and exit if the client exits? It's probably not too much of an issue for my app, which holds a long term connection in a single process, but just wondering what the best way to do this is.
I see there is also some mention of connection pooling. If the connections are passed around to different processes that might use them, maybe even start_link doesn't deal with leaks, and the connections have to be gc'd somehow. I was a little surprised to find that the connections are processes rather than ports. I'm guessing the reason is to be able to communicate with them from multiple clients.
Does this make sense?
— Reply to this email directly or view it on GitHubhttps://github.com/gar1t/erlang-redis/issues/1#issuecomment-19129928 .
The caller can monitor the redis connection, but I don't see how to get it the other way around (the connection monitors the caller). The idea is for the connection to automatically close itself if the caller exits, but for the caller to be able to keep running if something happens to the connection.
That's the case for a link. There's no obvious case to me where you wouldn't want one -- but the start function is canonical for OTP processes, so it's not a bad thing to have. As for the client process monitoring the user, this is hard and I'd argue a bad idea -- particularly because it's impossible to know who might use the process. You might have multiple users. The one approach that you can be certain of is that a depending process links to the client.
In the dbservice example, there is a very short period in which the client process could be orphaned (between start and link) -- and so that call could probably get converted to connect_link. That would require a clause in handle_info to deal with the EXIT as a no-op, as the error handling code would already have been kicked off when the process start failed.
On Fri, Jun 7, 2013 at 4:13 PM, paul-mhq [email protected] wrote:
The caller can monitor the redis connection, but I don't see how to get it the other way around (the connection monitors the caller). The idea is for the connection to automatically close itself if the caller exits, but for the caller to be able to keep running if something happens to the connection.
— Reply to this email directly or view it on GitHubhttps://github.com/gar1t/erlang-redis/issues/1#issuecomment-19133323 .