- I switched ECM over to using a straight nodejs TCP server.
- I learned about parsing HTTP packets from a buffer.
- I resolved to use a single process to respond to ejabberd_http.
The primary issue I have with ejabberd_http is this: what happens if the call comes in to megaphone_socket for data on a connection, and there is no data available?
Normally, with a separate process, the answer is relatively simple: you just call receive and wait for someone else to hand you some data. My previous decision regarding processes --- that I should create as few of them as possible --- complicates matters.
Trying to understand this, I came up with the following event sequence diagrams:
data is available at the time of call
ejabberd megaphone_ megaphone megaphone_ gen_tcp
http socket tcp
| | | | |
| | | recv(Socket) |
| | | --------------->|
| | | (data) |
| | | |<---------------
| | |data_received(data) |
| | |<--------------- |
| | | | |
<megaphone parses out the connection ID>
<Nobody is registered to receive updates about this connection so no
messages go out>
| | | | |
start(connection ID) | | |
|<------------------------------- | |
recv (connection ID) | | |
--------------->| | | |
| get_data (connection ID) | |
| --------------->| | |
| | | | |
< megaphone gets the data from the dictionary of connection data >
| | | | |
| (return (data)) | | |
| |<--------------- | |
|{ok, http_request } | | |
|<--------------- | | |
| | | | |
data is not available at the time of call
ejabberd megaphone_ megaphone megaphone_ gen_tcp
http socket tcp
| | | | |
| | | recv(Socket) |
| | | --------------->|
| | | (data) |
| | | |<---------------
| | |data_received(data) |
| | |<--------------- |
| | | recv(Socket) |
| | | --------------->|
| | | | |
<megaphone parses out the connection ID>
<Nobody is registered to receive updates about this connection so no
messages go out>
| | | | |
start(connection ID) | | |
|<------------------------------- | |
| | | | |
...
| | | | |
recv (connection ID) | | |
--------------->| | | |
| get_data (connection ID) | |
| --------------->| | |
| | | | |
< megaphone notes that there is no data for the provided connection ID >
| | | | |
| (return, no data) | |
| |<--------------- | |
| receive | | |
| -------\ | | |
| |<-----/ | | |
| | | | |
< the ejabberd_http process waits on the call the recv, which in
turn, waits on the call to receive>
...
| | | | |
| | | (data) |
| | | |<---------------
| | |data | |
| | |<--------------- |
| | | | |
< megaphone notes that this is for a connection that has a registered
listener >
| | | | |
| data (data) | | |
| |<--------------- | |
|{ok, http_request } | | |
|<--------------- | | |
| | | | |
This requires the creation of a new process: megaphone_tcp. This is something that sits around and listens for new TCP data to become available. It also requires the creation of the megaphone process: the basic purpose of that actor is to synchronize access to connection data that is shared by all the ejabberd_http processes that need data.Trying to understand this, I came up with the following event sequence diagrams:
data is available at the time of call
ejabberd megaphone_ megaphone megaphone_ gen_tcp
http socket tcp
| | | | |
| | | recv(Socket) |
| | | --------------->|
| | | (data) |
| | | |<---------------
| | |data_received(data) |
| | |<--------------- |
| | | | |
<megaphone parses out the connection ID>
<Nobody is registered to receive updates about this connection so no
messages go out>
| | | | |
start(connection ID) | | |
|<------------------------------- | |
recv (connection ID) | | |
--------------->| | | |
| get_data (connection ID) | |
| --------------->| | |
| | | | |
< megaphone gets the data from the dictionary of connection data >
| | | | |
| (return (data)) | | |
| |<--------------- | |
|{ok, http_request } | | |
|<--------------- | | |
| | | | |
data is not available at the time of call
ejabberd megaphone_ megaphone megaphone_ gen_tcp
http socket tcp
| | | | |
| | | recv(Socket) |
| | | --------------->|
| | | (data) |
| | | |<---------------
| | |data_received(data) |
| | |<--------------- |
| | | recv(Socket) |
| | | --------------->|
| | | | |
<megaphone parses out the connection ID>
<Nobody is registered to receive updates about this connection so no
messages go out>
| | | | |
start(connection ID) | | |
|<------------------------------- | |
| | | | |
...
| | | | |
recv (connection ID) | | |
--------------->| | | |
| get_data (connection ID) | |
| --------------->| | |
| | | | |
< megaphone notes that there is no data for the provided connection ID >
| | | | |
| (return, no data) | |
| |<--------------- | |
| receive | | |
| -------\ | | |
| |<-----/ | | |
| | | | |
< the ejabberd_http process waits on the call the recv, which in
turn, waits on the call to receive>
...
| | | | |
| | | (data) |
| | | |<---------------
| | |data | |
| | |<--------------- |
| | | | |
< megaphone notes that this is for a connection that has a registered
listener >
| | | | |
| data (data) | | |
| |<--------------- | |
|{ok, http_request } | | |
|<--------------- | | |
| | | | |
The whole notion of managing subscriptions to data for each connection may or may not actually be necessary. It really depends on how ejabberd_http expects to receive data: if it wants to receive new packets via calling receive, then something like a separate megaphone process is needed because ejabberd_http will end up calling megaphone_socket to get each packet.
A separate process is not needed if ejabberd_http processes one posting and then terminates the associated erlang process. This is because ejabberd_http will always be started in response to megaphone receiving a new, complete packet. megaphone should always have the data that ejabberd_http wants.
So the next steps are to create the megaphone and megaphone_tcp processes.
No comments:
Post a Comment