Replace aiohttp with httpx
This commit is contained in:
parent
46ffe7a70e
commit
299d644bc4
15 changed files with 40 additions and 95 deletions
4
.vscode/settings.json
vendored
4
.vscode/settings.json
vendored
|
|
@ -14,6 +14,7 @@
|
||||||
"finalise",
|
"finalise",
|
||||||
"finalised",
|
"finalised",
|
||||||
"gridfs",
|
"gridfs",
|
||||||
|
"httpx",
|
||||||
"iloc",
|
"iloc",
|
||||||
"initialisation",
|
"initialisation",
|
||||||
"initialised",
|
"initialised",
|
||||||
|
|
@ -62,7 +63,8 @@
|
||||||
"**/.mypy_cache": true,
|
"**/.mypy_cache": true,
|
||||||
"**/.pytest_cache": true,
|
"**/.pytest_cache": true,
|
||||||
"**/*.egg-info": true,
|
"**/*.egg-info": true,
|
||||||
"**/*.cache": true
|
"**/*.cache": true,
|
||||||
|
"**/tracing_database.json": true
|
||||||
},
|
},
|
||||||
"notebook.output.textLineLimit": 400,
|
"notebook.output.textLineLimit": 400,
|
||||||
"python.defaultInterpreterPath": ".env/bin/python",
|
"python.defaultInterpreterPath": ".env/bin/python",
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,10 @@ __version__ = "0.0.12"
|
||||||
|
|
||||||
from .context import configure
|
from .context import configure
|
||||||
from .deploy import GreatAI
|
from .deploy import GreatAI
|
||||||
from .exceptions import (
|
from .errors import (
|
||||||
ArgumentValidationError,
|
ArgumentValidationError,
|
||||||
MissingArgumentError,
|
MissingArgumentError,
|
||||||
|
RemoteCallError,
|
||||||
WrongDecoratorOrderError,
|
WrongDecoratorOrderError,
|
||||||
)
|
)
|
||||||
from .models import save_model, use_model
|
from .models import save_model, use_model
|
||||||
|
|
@ -15,13 +16,9 @@ from .output_views import (
|
||||||
MultiLabelClassificationOutput,
|
MultiLabelClassificationOutput,
|
||||||
RegressionOutput,
|
RegressionOutput,
|
||||||
)
|
)
|
||||||
from .parameters import log_metric, parameter
|
from .parameters.log_metric import log_metric
|
||||||
|
from .parameters.parameter import parameter
|
||||||
from .persistence import MongodbDriver, ParallelTinyDbDriver, TracingDatabaseDriver
|
from .persistence import MongodbDriver, ParallelTinyDbDriver, TracingDatabaseDriver
|
||||||
from .remote import (
|
from .remote import call_remote_great_ai, call_remote_great_ai_async
|
||||||
HttpClient,
|
|
||||||
RemoteCallError,
|
|
||||||
call_remote_great_ai,
|
|
||||||
call_remote_great_ai_async,
|
|
||||||
)
|
|
||||||
from .tracing import add_ground_truth, delete_ground_truth, query_ground_truth
|
from .tracing import add_ground_truth, delete_ground_truth, query_ground_truth
|
||||||
from .views import RouteConfig, Trace
|
from .views import RouteConfig, Trace
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ from watchdog.observers import Observer
|
||||||
from great_ai.constants import SERVER_NAME
|
from great_ai.constants import SERVER_NAME
|
||||||
from great_ai.context import _is_in_production_mode
|
from great_ai.context import _is_in_production_mode
|
||||||
from great_ai.deploy import GreatAI
|
from great_ai.deploy import GreatAI
|
||||||
from great_ai.exceptions import ArgumentValidationError, MissingArgumentError
|
from great_ai.errors import ArgumentValidationError, MissingArgumentError
|
||||||
from great_ai.utilities import get_logger
|
from great_ai.utilities import get_logger
|
||||||
|
|
||||||
from .parse_arguments import parse_arguments
|
from .parse_arguments import parse_arguments
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
from .argument_validation_error import ArgumentValidationError
|
from .argument_validation_error import ArgumentValidationError
|
||||||
from .missing_argument_error import MissingArgumentError
|
from .missing_argument_error import MissingArgumentError
|
||||||
|
from .remote_call_error import RemoteCallError
|
||||||
from .wrong_decorator_order_error import WrongDecoratorOrderError
|
from .wrong_decorator_order_error import WrongDecoratorOrderError
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
from typing import Callable
|
from typing import Callable
|
||||||
|
|
||||||
from ..exceptions import WrongDecoratorOrderError
|
from ..errors import WrongDecoratorOrderError
|
||||||
from .get_function_metadata_store import get_function_metadata_store
|
from .get_function_metadata_store import get_function_metadata_store
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
from .automatically_decorate_parameters import automatically_decorate_parameters
|
|
||||||
from .log_metric import log_metric
|
|
||||||
from .parameter import parameter
|
|
||||||
|
|
@ -3,7 +3,7 @@ from typing import Any, Callable, Dict, TypeVar, cast
|
||||||
|
|
||||||
from typeguard import check_type
|
from typeguard import check_type
|
||||||
|
|
||||||
from ..exceptions import ArgumentValidationError
|
from ..errors import ArgumentValidationError
|
||||||
from ..helper import get_arguments, get_function_metadata_store
|
from ..helper import get_arguments, get_function_metadata_store
|
||||||
from ..helper.assert_function_is_not_finalised import assert_function_is_not_finalised
|
from ..helper.assert_function_is_not_finalised import assert_function_is_not_finalised
|
||||||
from ..tracing.tracing_context import TracingContext
|
from ..tracing.tracing_context import TracingContext
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,2 @@
|
||||||
from .call_remote_great_ai import call_remote_great_ai
|
from .call_remote_great_ai import call_remote_great_ai
|
||||||
from .call_remote_great_ai_async import call_remote_great_ai_async
|
from .call_remote_great_ai_async import call_remote_great_ai_async
|
||||||
from .http_client import HttpClient
|
|
||||||
from .remote_call_error import RemoteCallError
|
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,10 @@
|
||||||
from typing import Any, Mapping, Optional, Type, TypeVar
|
from typing import Any, Mapping, Optional, Type, TypeVar
|
||||||
|
|
||||||
|
import httpx
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
from ..errors.remote_call_error import RemoteCallError
|
||||||
from ..views import Trace
|
from ..views import Trace
|
||||||
from .http_client import HttpClient
|
|
||||||
from .remote_call_error import RemoteCallError
|
|
||||||
|
|
||||||
http: Optional[HttpClient] = None
|
|
||||||
|
|
||||||
T = TypeVar("T", bound=BaseModel)
|
T = TypeVar("T", bound=BaseModel)
|
||||||
|
|
||||||
|
|
@ -15,23 +13,35 @@ async def call_remote_great_ai_async(
|
||||||
base_uri: str,
|
base_uri: str,
|
||||||
data: Mapping[str, Any],
|
data: Mapping[str, Any],
|
||||||
retry_count: int = 4,
|
retry_count: int = 4,
|
||||||
|
timeout_in_seconds: int = 60,
|
||||||
model_class: Optional[Type[T]] = None,
|
model_class: Optional[Type[T]] = None,
|
||||||
) -> Trace[T]:
|
) -> Trace[T]:
|
||||||
global http
|
|
||||||
if http is None:
|
|
||||||
http = HttpClient()
|
|
||||||
|
|
||||||
if base_uri.endswith("/"):
|
if base_uri.endswith("/"):
|
||||||
base_uri = base_uri[:-1]
|
base_uri = base_uri[:-1]
|
||||||
|
|
||||||
url = f"{base_uri}/predict/"
|
if not base_uri.endswith("/predict"):
|
||||||
response = await http.post(
|
base_uri = f"{base_uri}/predict"
|
||||||
url=url, data=data, retry_count=retry_count, expected_status=200
|
|
||||||
)
|
transport = httpx.AsyncHTTPTransport(retries=retry_count)
|
||||||
|
async with httpx.AsyncClient(
|
||||||
|
transport=transport, timeout=timeout_in_seconds
|
||||||
|
) as client:
|
||||||
|
response = await client.post(base_uri, json=data)
|
||||||
|
try:
|
||||||
|
response.raise_for_status()
|
||||||
|
except Exception:
|
||||||
|
raise RemoteCallError("Unexpected status code")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if model_class is not None:
|
trace = response.json()
|
||||||
response["output"] = model_class.parse_obj(response["output"])
|
|
||||||
return Trace.parse_obj(response)
|
|
||||||
except Exception:
|
except Exception:
|
||||||
raise RemoteCallError("Could not parse response")
|
raise RemoteCallError(
|
||||||
|
f"JSON parsing failed {response.text}",
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
if model_class is not None:
|
||||||
|
trace["output"] = model_class.parse_obj(trace["output"])
|
||||||
|
return Trace.parse_obj(trace)
|
||||||
|
except Exception:
|
||||||
|
raise RemoteCallError("Could not parse Trace")
|
||||||
|
|
|
||||||
|
|
@ -1,60 +0,0 @@
|
||||||
import logging
|
|
||||||
from asyncio import sleep
|
|
||||||
from typing import Any, Mapping, Optional
|
|
||||||
|
|
||||||
import aiohttp
|
|
||||||
|
|
||||||
from .remote_call_error import RemoteCallError
|
|
||||||
|
|
||||||
logger = logging.getLogger("http")
|
|
||||||
|
|
||||||
|
|
||||||
class HttpClient:
|
|
||||||
timeout_seconds: int = 600
|
|
||||||
wait_between_retries_seconds: float = 5
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
) -> None:
|
|
||||||
timeout = aiohttp.ClientTimeout(total=self.timeout_seconds)
|
|
||||||
|
|
||||||
self._session = aiohttp.ClientSession(
|
|
||||||
raise_for_status=False,
|
|
||||||
timeout=timeout,
|
|
||||||
)
|
|
||||||
|
|
||||||
async def post(
|
|
||||||
self,
|
|
||||||
url: str,
|
|
||||||
data: Mapping[str, Any],
|
|
||||||
retry_count: int = 0,
|
|
||||||
expected_status: Optional[int] = None,
|
|
||||||
**kwargs: Any,
|
|
||||||
) -> Any:
|
|
||||||
for i in range(retry_count + 1):
|
|
||||||
try:
|
|
||||||
async with self._session.post(url, json=data, **kwargs) as r:
|
|
||||||
if (
|
|
||||||
expected_status is not None and r.status != expected_status
|
|
||||||
) or r.status >= 500:
|
|
||||||
response_text = await r.text()
|
|
||||||
raise ValueError(
|
|
||||||
f"Found not-expected status code: {r.status}, response is: {response_text}"
|
|
||||||
)
|
|
||||||
try:
|
|
||||||
return await r.json()
|
|
||||||
except Exception:
|
|
||||||
raise RemoteCallError(
|
|
||||||
"JSON parsing failed",
|
|
||||||
)
|
|
||||||
except Exception as e:
|
|
||||||
if retry_count - i > 1:
|
|
||||||
logger.warning(
|
|
||||||
f"Request failed ({e}), {retry_count - i - 1} retries left",
|
|
||||||
)
|
|
||||||
await sleep(self.wait_between_retries_seconds)
|
|
||||||
|
|
||||||
raise RemoteCallError(f"Request has failed too many ({retry_count + 1}) times")
|
|
||||||
|
|
||||||
async def close(self) -> None:
|
|
||||||
await self._session.close()
|
|
||||||
|
|
@ -37,10 +37,11 @@ dependencies = [
|
||||||
"uvicorn[standard] >= 0.18.0",
|
"uvicorn[standard] >= 0.18.0",
|
||||||
"watchdog >= 2.1.0",
|
"watchdog >= 2.1.0",
|
||||||
"typeguard >= 2.10.0",
|
"typeguard >= 2.10.0",
|
||||||
"pymongo >= 3.0.0",
|
"pymongo >= 4.0.0",
|
||||||
"dill >= 0.3.5.0",
|
"dill >= 0.3.5.0",
|
||||||
|
'tqdm',
|
||||||
"async_lru >= 1.0.0",
|
"async_lru >= 1.0.0",
|
||||||
"aiohttp[speedups] >= 3.8.0",
|
"httpx >= 0.20.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[project.optional-dependencies]
|
[project.optional-dependencies]
|
||||||
|
|
@ -60,7 +61,6 @@ dev = [
|
||||||
"pytest-cov",
|
"pytest-cov",
|
||||||
"pytest-subtests",
|
"pytest-subtests",
|
||||||
"pytest-asyncio",
|
"pytest-asyncio",
|
||||||
'tqdm',
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[project.urls]
|
[project.urls]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue