From 8a5d6ec74d5dfc3fd04aab679a5d77902a0fe617 Mon Sep 17 00:00:00 2001 From: Andrey Date: Wed, 12 Apr 2023 11:25:14 +0300 Subject: [PATCH] Add "request_queue_size" option to REST API server (#2643) Sets request queue size for TCP socket used by Patroni REST API. Once the queue is full, further requests get a "Connection denied" error. The default value is 5. --- docs/ENVIRONMENT.rst | 2 ++ docs/SETTINGS.rst | 1 + patroni/api.py | 1 + patroni/config.py | 17 ++++++++++------- patroni/validator.py | 3 ++- 5 files changed, 16 insertions(+), 8 deletions(-) diff --git a/docs/ENVIRONMENT.rst b/docs/ENVIRONMENT.rst index edb62c77..75e195c3 100644 --- a/docs/ENVIRONMENT.rst +++ b/docs/ENVIRONMENT.rst @@ -187,6 +187,8 @@ REST API - **PATRONI\_RESTAPI\_ALLOWLIST\_INCLUDE\_MEMBERS**: (optional): If set to ``true`` it allows accessing unsafe REST API endpoints from other cluster members registered in DCS (IP address or hostname is taken from the members ``api_url``). Be careful, it might happen that OS will use a different IP for outgoing connections. - **PATRONI\_RESTAPI\_HTTP\_EXTRA\_HEADERS**: (optional) HTTP headers let the REST API server pass additional information with an HTTP response. - **PATRONI\_RESTAPI\_HTTPS\_EXTRA\_HEADERS**: (optional) HTTPS headers let the REST API server pass additional information with an HTTP response when TLS is enabled. This will also pass additional information set in ``http_extra_headers``. +- **PATRONI\_RESTAPI\_REQUEST\_QUEUE\_SIZE**: (optional): Sets request queue size for TCP socket used by Patroni REST API. Once the queue is full, further requests get a "Connection denied" error. The default value is 5. +- ``` CTL --- diff --git a/docs/SETTINGS.rst b/docs/SETTINGS.rst index 4577f15c..538f99dd 100644 --- a/docs/SETTINGS.rst +++ b/docs/SETTINGS.rst @@ -352,6 +352,7 @@ REST API - **allowlist\_include\_members**: (optional): If set to ``true`` it allows accessing unsafe REST API endpoints from other cluster members registered in DCS (IP address or hostname is taken from the members ``api_url``). Be careful, it might happen that OS will use a different IP for outgoing connections. - **http\_extra\_headers**: (optional): HTTP headers let the REST API server pass additional information with an HTTP response. - **https\_extra\_headers**: (optional): HTTPS headers let the REST API server pass additional information with an HTTP response when TLS is enabled. This will also pass additional information set in ``http_extra_headers``. + - **request_queue_size**: (optional): Sets request queue size for TCP socket used by Patroni REST API. Once the queue is full, further requests get a "Connection denied" error. The default value is 5. Here is an example of both **http_extra_headers** and **https_extra_headers**: diff --git a/patroni/api.py b/patroni/api.py index e5b8e6fb..45b50a4d 100644 --- a/patroni/api.py +++ b/patroni/api.py @@ -759,6 +759,7 @@ class RestApiServer(ThreadingMixIn, HTTPServer, Thread): def __init__(self, patroni, config): self.patroni = patroni self.__listen = None + self.request_queue_size = int(config.get('request_queue_size', 5)) self.__ssl_options = None self.__ssl_serial_number = None self._received_new_cert = False diff --git a/patroni/config.py b/patroni/config.py index 6d4a1cb0..1e98a7c7 100644 --- a/patroni/config.py +++ b/patroni/config.py @@ -378,7 +378,8 @@ class Config(object): _set_section_values('restapi', ['listen', 'connect_address', 'certfile', 'keyfile', 'keyfile_password', 'cafile', 'ciphers', 'verify_client', 'http_extra_headers', - 'https_extra_headers', 'allowlist', 'allowlist_include_members']) + 'https_extra_headers', 'allowlist', 'allowlist_include_members', + 'request_queue_size']) _set_section_values('ctl', ['insecure', 'cacert', 'certfile', 'keyfile', 'keyfile_password']) _set_section_values('postgresql', ['listen', 'connect_address', 'proxy_address', 'config_dir', 'data_dir', 'pgpass', 'bin_dir']) @@ -393,12 +394,14 @@ class Config(object): if value is not None: ret[first][second] = value - for second in ('max_queue_size', 'file_size', 'file_num'): - value = ret.get('log', {}).pop(second, None) - if value: - value = parse_int(value) - if value is not None: - ret['log'][second] = value + for first, params in (('restapi', ('request_queue_size',)), + ('log', ('max_queue_size', 'file_size', 'file_num'))): + for second in params: + value = ret.get(first, {}).pop(second, None) + if value: + value = parse_int(value) + if value is not None: + ret[first][second] = value def _parse_list(value): if not (value.strip().startswith('-') or '[' in value): diff --git a/patroni/validator.py b/patroni/validator.py index 890b3d56..ecd3bc58 100644 --- a/patroni/validator.py +++ b/patroni/validator.py @@ -703,7 +703,8 @@ schema = Schema({ "scope": str, "restapi": { "listen": validate_host_port_listen, - "connect_address": validate_connect_address + "connect_address": validate_connect_address, + Optional("request_queue_size"): lambda i: assert_(0 <= int(i) <= 4096) }, Optional("bootstrap"): { "dcs": {