Skip to content

Commit

Permalink
[ADD] server: allow env variable to control HTTP socket timeout
Browse files Browse the repository at this point in the history
As indicated in the comment, it's much preferred to perform response
buffering at the reverse proxy level than to increase the socket
timeout. It will free up HTTP workers for other requests faster, while
the proxy does the work of buffering the stream on disk as needed.

/!\ The timeout is also used to protect from accidental DoS effects
in situations of low worker availability, due to idle connections
caused e.g. by wkhtmltopdf's connection pooling.
Setting a high timeout will make the protection less effective, so
ensuring you have enough free HTTP workers at all times becomes critical.

In our tests with nginx's defaut buffering on a typical hardware with
SSD storage, buffering up to 1GB responses did not require any change
of the socket timeout on the Odoo side, though your mileage may vary.
See also nginx's `proxy_buffering` and `proxy_max_temp_file_size` config
directives.

OPW-2247730
See also: odoo#20158

closes odoo#51824

Signed-off-by: Olivier Dony (odo) <odo@openerp.com>
  • Loading branch information
odony committed May 25, 2020
1 parent 4758a06 commit d78ea12
Showing 1 changed file with 12 additions and 1 deletion.
13 changes: 12 additions & 1 deletion odoo/service/server.py
Expand Up @@ -869,9 +869,20 @@ def _runloop(self):

class WorkerHTTP(Worker):
""" HTTP Request workers """
def __init__(self, multi):
super(WorkerHTTP, self).__init__(multi)

# The ODOO_HTTP_SOCKET_TIMEOUT environment variable allows to control socket timeout for
# extreme latency situations. It's generally better to use a good buffering reverse proxy
# to quickly free workers rather than increasing this timeout to accomodate high network
# latencies & b/w saturation. This timeout is also essential to protect against accidental
# DoS due to idle HTTP connections.
sock_timeout = os.environ.get("ODOO_HTTP_SOCKET_TIMEOUT")
self.sock_timeout = float(sock_timeout) if sock_timeout else 2

def process_request(self, client, addr):
client.setblocking(1)
client.settimeout(2)
client.settimeout(self.sock_timeout)
client.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
# Prevent fd inherientence close_on_exec
flags = fcntl.fcntl(client, fcntl.F_GETFD) | fcntl.FD_CLOEXEC
Expand Down

0 comments on commit d78ea12

Please sign in to comment.