diff --git a/python/cuopt_self_hosted/cuopt_sh_client/cuopt_self_host_client.py b/python/cuopt_self_hosted/cuopt_sh_client/cuopt_self_host_client.py index 7418516f99..3cbd54829d 100644 --- a/python/cuopt_self_hosted/cuopt_sh_client/cuopt_self_host_client.py +++ b/python/cuopt_self_hosted/cuopt_sh_client/cuopt_self_host_client.py @@ -21,6 +21,7 @@ import time import zlib from enum import Enum +from types import NoneType from uuid import UUID import cuopt_mps_parser @@ -291,6 +292,20 @@ class CuOptServiceSelfHostClient: wildcard is used, the result mime_type will be set to the content_type mime_type of the original request. If not provided, result_type defaults to mime_type.MSGPACK + http_general_timeout: int + The time in seconds that http will wait before timing out + on a general request such as a job status check. Default is 30s. + Set to None to never timeout. + data_send_timeout: int + The time in seconds that http will wait before timing out + on a problem submission to the server. If set to -1, + the http_general_timeout value will be used. Default is -1. + Set to None to never timeout. + result_receive_timeout: int + The time in seconds that http will wait before timing out + on receiving a result from the server. If set to -1, + the http_general_timeout value will be used. Default is -1. + Set to None to never timeout. """ # Initialize the CuOptServiceSelfHostClient @@ -306,6 +321,9 @@ def __init__( polling_timeout=600, timeout_exception=True, result_type=mime_type.MSGPACK, + http_general_timeout=30, + data_send_timeout=-1, + result_receive_timeout=-1, ): self.timeout_exception = timeout_exception self.ip = ip @@ -313,6 +331,23 @@ def __init__( self.only_validate = only_validate self.accept_type = result_type + if not isinstance(http_general_timeout, (NoneType, int, float)): + raise ValueError("Incompatible value for http_general_timeout") + + self.http_general_timeout = http_general_timeout + self.data_send_timeout = ( + data_send_timeout + if isinstance(data_send_timeout, (NoneType, int, float)) + and data_send_timeout != -1 + else self.http_general_timeout + ) + self.result_receive_timeout = ( + result_receive_timeout + if isinstance(result_receive_timeout, (NoneType, int, float)) + and result_receive_timeout != -1 + else self.http_general_timeout + ) + self.protocol = "https" if use_https else "http" self.verify = False if use_https is True: @@ -377,7 +412,7 @@ def _get_logs(self, reqId, logging_callback): verify=self.verify, headers=headers, params=params, - timeout=30, + timeout=self.http_general_timeout, ) # File has not been created yet @@ -404,7 +439,7 @@ def _get_incumbents(self, reqId, incumbent_callback): self.solution_url + f"/{reqId}/incumbents", verify=self.verify, headers=headers, - timeout=30, + timeout=self.http_general_timeout, ) response.raise_for_status() response = self._get_response(response) @@ -513,7 +548,7 @@ def stop_threads(log_t, inc_t, done): self.solution_url + f"/{reqId}", verify=self.verify, headers=headers, - timeout=30, + timeout=self.result_receive_timeout, ) response.raise_for_status() response = self._get_response(response) @@ -594,7 +629,7 @@ def serialize(cuopt_problem_data): data=data, headers=headers, verify=self.verify, - timeout=30, + timeout=self.data_send_timeout, ) response.raise_for_status() log.debug(response.status_code) @@ -853,7 +888,7 @@ def delete(self, id, running=None, queued=None, cached=None): "cached": cached, }, verify=self.verify, - timeout=30, + timeout=self.http_general_timeout, ) response.raise_for_status() log.debug(response.status_code) @@ -887,7 +922,7 @@ def delete_solution(self, id): self.solution_url + f"/{id}", headers=headers, verify=self.verify, - timeout=30, + timeout=self.http_general_timeout, ) response.raise_for_status() log.debug(response.status_code) @@ -898,7 +933,7 @@ def delete_solution(self, id): response = requests.delete( self.log_url + f"/{id}", verify=self.verify, - timeout=30, + timeout=self.http_general_timeout, ) except Exception: pass @@ -938,7 +973,7 @@ def repoll(self, data, response_type="obj", delete_solution=True): self.solution_url + f"/{data}", verify=self.verify, headers=headers, - timeout=30, + timeout=self.result_receive_timeout, ) response.raise_for_status() except requests.exceptions.HTTPError as e: @@ -976,7 +1011,7 @@ def status(self, id): self.request_url + f"/{id}?status", verify=self.verify, headers=headers, - timeout=30, + timeout=self.http_general_timeout, ) response.raise_for_status() except requests.exceptions.HTTPError as e: @@ -1014,7 +1049,7 @@ def upload_solution(self, solution): verify=self.verify, data=data, headers=headers, - timeout=30, + timeout=self.data_send_timeout, ) response.raise_for_status() except requests.exceptions.HTTPError as e: diff --git a/python/cuopt_self_hosted/cuopt_sh_client/cuopt_sh.py b/python/cuopt_self_hosted/cuopt_sh_client/cuopt_sh.py index 56763bcb8a..7193d62f4b 100755 --- a/python/cuopt_self_hosted/cuopt_sh_client/cuopt_sh.py +++ b/python/cuopt_self_hosted/cuopt_sh_client/cuopt_sh.py @@ -48,6 +48,7 @@ def status(args): self_signed_cert=args.self_signed_cert, timeout_exception=False, result_type=result_types[args.result_type], + http_general_timeout=args.http_timeout, ) try: @@ -73,6 +74,7 @@ def delete_request(args): self_signed_cert=args.self_signed_cert, timeout_exception=False, result_type=result_types[args.result_type], + http_general_timeout=args.http_timeout, ) try: @@ -104,6 +106,7 @@ def upload_solution(args): self_signed_cert=args.self_signed_cert, timeout_exception=False, result_type=result_types[args.result_type], + http_general_timeout=args.http_timeout, ) try: @@ -129,6 +132,7 @@ def delete_solution(args): self_signed_cert=args.self_signed_cert, timeout_exception=False, result_type=result_types[args.result_type], + http_general_timeout=args.http_timeout, ) try: @@ -220,6 +224,7 @@ def read_input_data(i_file): only_validate=args.only_validation, timeout_exception=False, result_type=result_types[args.result_type], + http_general_timeout=args.http_timeout, ) try: @@ -587,6 +592,16 @@ def main(): help="Upload a solution to be cached on the server. The reqId " "returned may be used as an initial solution for VRP.", ) + parser.add_argument( + "-ht", + "--http-timeout", + type=int, + default=30, + help="Timeout in seconds for http requests. May need to be increased " + "for large datasets or slow networks. Default is 30s. " + "Set to None to never timeout.", + ) + args = parser.parse_args() set_log_level(levels[args.log_level]) if args.version: