marcelog
marcelog

Reputation: 7180

How to call (and sleep) on gen_tcp:accept and still process system messages at the same time?

I'm still kind of new to the erlang/otp world, so I guess this is a pretty basic question. Nevertheless I'd like to know what's the correct way of doing the following.

Currently, I have an application with a top supervisor. The latter will supervise workers that call gen_tcp:accept (sleeping on it) and then spawn a process for each accepted connection. Note: To this question, it is irrelevant where the listen() is done.

My question is about the correct way of making these workers (the ones that sleep on gen_tcp:accept) respect the otp design principles, in such a way that they can handle system messages (to handle shutdown, trace, etc), according to what I've read here: http://www.erlang.org/doc/design_principles/spec_proc.html

So,

Thanks in advance :)

Upvotes: 4

Views: 773

Answers (3)

marcelog
marcelog

Reputation: 7180

I've actually found the answer in another question: Non-blocking TCP server using OTP principles and here http://20bits.com/article/erlang-a-generalized-tcp-server

EDIT: The specific answer that was helpful to me was: https://stackoverflow.com/a/6513913/727142

Upvotes: 1

mlb
mlb

Reputation: 1351

As Erlang is event driven, it is awkward to deal with code that blocks as accept/{1,2} does.

Personally, I would have a supervisor which has a gen_server for the listener, and another supervisor for the accept workers. Handroll an accept worker to timeout (gen_tcp:accept/2), effectively polling, (the awkward part) rather than receiving an message for status.

This way, if a worker dies, it gets restarted by the supervisor above it. If the listener dies, it restarts, but not before restarting the worker tree and supervisor that depended on that listener. Of course, if the top supervisor dies, it gets restarted. However, if you supervisor:terminate_child/2 on the tree, then you can effectively disable the listener and all acceptors for that socket. Later, supervisor:restart_child/2 can restart the whole listener+acceptor worker pool.

If you want an app to manage this for you, cowboy implements the above. Although http oriented, it easily supports a custom handler for whatever protocol to be used instead.

Upvotes: 1

Alin
Alin

Reputation: 818

You can make it as a gen_server similar to this one: https://github.com/alinpopa/qerl/blob/master/src/qerl_conn_listener.erl.

As you can see, this process is doing tcp accept and processing other messages (e.g. stop(Pid) -> gen_server:cast(Pid,{close}).)

HTH, Alin

Upvotes: 0

Related Questions