[enh] Add timeout limit per request (#1640)

The new url parameter "timeout_limit" set timeout limit defined in second.
Example "timeout_limit=1.5" means the timeout limit is 1.5 seconds.

In addition, the query can start with <[number] to set the timeout limit.

For number between 0 and 99, the unit is the second :
Example: "<30 searx" means the timeout limit is 3 seconds

For number above 100, the unit is the millisecond:
Example: "<850 searx" means the timeout is 850 milliseconds.

In addition, there is a new optional setting: outgoing.max_request_timeout.
If not set, the user timeout can't go above searx configuration (as before: the max timeout of selected engine for a query).

If the value is set, the user can set a timeout between 0 and max_request_timeout using
<[number] or timeout_limit query parameter.

Related to #1077
Updated version of PR #1413 from @isj-privacore
This commit is contained in:
Alexandre Flament 2019-08-02 13:50:51 +02:00 committed by GitHub
parent 2179079a91
commit 72029d27de
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 180 additions and 15 deletions

View file

@ -45,6 +45,16 @@ if sys.version_info[0] == 3:
logger = logger.getChild('search')
number_of_searches = 0
max_request_timeout = settings.get('outgoing', {}).get('max_request_timeout' or None)
if max_request_timeout is None:
logger.info('max_request_timeout={0}'.format(max_request_timeout))
else:
if isinstance(max_request_timeout, float):
logger.info('max_request_timeout={0} second(s)'.format(max_request_timeout))
else:
logger.critical('outgoing.max_request_timeout if defined has to be float')
from sys import exit
exit(1)
def send_http_request(engine, request_params):
@ -265,6 +275,15 @@ def get_search_query_from_webapp(preferences, form):
# query_engines
query_engines = raw_text_query.engines
# timeout_limit
query_timeout = raw_text_query.timeout_limit
if query_timeout is None and 'timeout_limit' in form:
raw_time_limit = form.get('timeout_limit')
try:
query_timeout = float(raw_time_limit)
except ValueError:
raise SearxParameterException('timeout_limit', raw_time_limit)
# query_categories
query_categories = []
@ -338,7 +357,8 @@ def get_search_query_from_webapp(preferences, form):
query_engines = deduplicate_query_engines(query_engines)
return (SearchQuery(query, query_engines, query_categories,
query_lang, query_safesearch, query_pageno, query_time_range),
query_lang, query_safesearch, query_pageno,
query_time_range, query_timeout),
raw_text_query)
@ -351,6 +371,7 @@ class Search(object):
super(Search, self).__init__()
self.search_query = search_query
self.result_container = ResultContainer()
self.actual_timeout = None
# do search-request
def search(self):
@ -380,7 +401,7 @@ class Search(object):
search_query = self.search_query
# max of all selected engine timeout
timeout_limit = 0
default_timeout = 0
# start search-reqest for all selected engines
for selected_engine in search_query.engines:
@ -420,12 +441,32 @@ class Search(object):
# append request to list
requests.append((selected_engine['name'], search_query.query, request_params))
# update timeout_limit
timeout_limit = max(timeout_limit, engine.timeout)
# update default_timeout
default_timeout = max(default_timeout, engine.timeout)
# adjust timeout
self.actual_timeout = default_timeout
query_timeout = self.search_query.timeout_limit
if max_request_timeout is None and query_timeout is None:
# No max, no user query: default_timeout
pass
elif max_request_timeout is None and query_timeout is not None:
# No max, but user query: From user query except if above default
self.actual_timeout = min(default_timeout, query_timeout)
elif max_request_timeout is not None and query_timeout is None:
# Max, no user query: Default except if above max
self.actual_timeout = min(default_timeout, max_request_timeout)
elif max_request_timeout is not None and query_timeout is not None:
# Max & user query: From user query except if above max
self.actual_timeout = min(query_timeout, max_request_timeout)
logger.debug("actual_timeout={0} (default_timeout={1}, ?timeout_limit={2}, max_request_timeout={3})"
.format(self.actual_timeout, default_timeout, query_timeout, max_request_timeout))
# send all search-request
if requests:
# send all search-request
search_multiple_requests(requests, self.result_container, start_time, timeout_limit)
search_multiple_requests(requests, self.result_container, start_time, self.actual_timeout)
start_new_thread(gc.collect, tuple())
# return results, suggestions, answers and infoboxes