{active, once}
is great - use it.Start with the basics:
gen_server:call
to singleton processes (and equivalent operations)eheap_alloc: Cannot allocate 1459620480 bytes of memory (of type "heap").
check_overload() -> case process_info(self(), message_queue_len) of {message_queue_len, N} when N > 100000 -> erlang:exit(stage_left); _ -> ok end.
That's great, but aren't we now silently losing messages?
gen_tcp:send(Port, Data, Timeout)
send(S, Packet) when is_port(S) -> case inet_db:lookup_socket(S) of {ok, Mod} -> Mod:send(S, Packet); Error -> Error end.
Mod
is always prim_inet
erlang:port_get_data/1
(Kinda wonder if I can find a use for that)send(S, Data) -> send(S, Data, []). send(S, Data, OptList) when is_port(S), is_list(OptList) -> try erlang:port_command(S, Data, OptList) of false -> % Port busy and nosuspend option passed {error,busy}; true -> receive {inet_reply,S,Status} -> Status end catch error:_Error -> {error,einval} end.
send(S, Data, Timeout) -> true = erlang:port_command(S, Data, []), receive {inet_reply, S, Status} -> Status after Timeout -> {error, timeout} end.
For extra credit, you can make this message based by starting a timer before the port command, and then watching for completion of the send by either an inet_reply
message or a timeout
message.
You can check your answer against our example in logplex_tcpsyslog_drain
.
For extra extra credit, you could do the same for connect.
Now we don't spend much time blocked, so we can keep up with our message queue
Code complexity has gone up
You can still get yourself a send timeout by doing the erlangy thing:
More processes
Move your use of the client code out to a separate process