RAPTOR v18.4: Исправлена отчетность, активированы выходные

This commit is contained in:
root
2026-04-18 23:26:45 +03:00
commit ef0958239e
312 changed files with 54247 additions and 0 deletions

View File

@@ -0,0 +1,21 @@
from t_tech.invest import AsyncClient
from t_tech.invest.retrying.aio.grpc_interceptor import AsyncRetryClientInterceptor
from t_tech.invest.retrying.aio.retry_manager import AsyncRetryManager
from t_tech.invest.retrying.settings_protocol import RetryClientSettingsProtocol
class AsyncRetryingClient(AsyncClient):
def __init__(
self,
token: str,
settings: RetryClientSettingsProtocol,
**kwargs,
):
self._retry_manager = AsyncRetryManager(settings=settings)
self._retry_interceptor = AsyncRetryClientInterceptor(
retry_manager=self._retry_manager
)
interceptors = kwargs.get("interceptors", [])
interceptors.append(self._retry_interceptor)
kwargs["interceptors"] = interceptors
super().__init__(token, **kwargs)

View File

@@ -0,0 +1,21 @@
import grpc
from t_tech.invest.retrying.aio.retry_manager import AsyncRetryManager
class AsyncRetryClientInterceptor(grpc.aio.UnaryUnaryClientInterceptor):
def __init__(
self, retry_manager: AsyncRetryManager
): # pylint: disable=super-init-not-called
self._retry_manager = retry_manager
async def _intercept_with_retry(self, continuation, client_call_details, request):
async def call():
return await continuation(client_call_details, request)
return await self._retry_manager.call_with_retries(call=call)
async def intercept_unary_unary(self, continuation, client_call_details, request):
return await self._intercept_with_retry(
continuation, client_call_details, request
)

View File

@@ -0,0 +1,35 @@
import asyncio
import logging
from typing import Any
from grpc.aio import AioRpcError
from t_tech.invest.logging import get_metadata_from_aio_error
from t_tech.invest.retrying.base_retry_manager import BaseRetryManager
logger = logging.getLogger(__name__)
class AsyncRetryManager(BaseRetryManager):
async def call_with_retries(self, call: Any):
retries_left = self.get_initial_retries()
while retries_left > 0:
logger.debug("Trying to call")
response = await call()
try:
await response
logger.debug("Call succeeded")
return response
except AioRpcError as exception:
retries_left -= 1
logger.debug("Retries left = %s", retries_left)
metadata = get_metadata_from_aio_error(exception)
seconds_to_sleep = self.extract_seconds_to_sleep(metadata)
await self._sleep(seconds_to_sleep)
logger.debug("RetryManager exhausted, no retries left")
return response
async def _sleep(self, seconds_to_sleep):
await asyncio.sleep(seconds_to_sleep)

View File

@@ -0,0 +1,25 @@
import logging
from t_tech.invest.retrying.settings_protocol import RetryClientSettingsProtocol
logger = logging.getLogger(__name__)
class BaseRetryManager:
def __init__(self, settings: RetryClientSettingsProtocol):
self._settings = settings
def get_initial_retries(self):
retries_left = self._settings.max_retry_attempt
if not self._settings.use_retry:
retries_left = 0
logger.debug("Retrying disabled")
retries_left += 1
return retries_left
@staticmethod
def extract_seconds_to_sleep(metadata) -> int:
logger.debug("Received metadata %s", metadata)
seconds_to_sleep = metadata.ratelimit_reset
logger.debug("Sleeping for %s seconds", seconds_to_sleep)
return seconds_to_sleep

View File

@@ -0,0 +1,9 @@
import dataclasses
from t_tech.invest.retrying.settings_protocol import RetryClientSettingsProtocol
@dataclasses.dataclass()
class RetryClientSettings(RetryClientSettingsProtocol):
use_retry: bool = True
max_retry_attempt: int = 3

View File

@@ -0,0 +1,6 @@
from typing import Protocol
class RetryClientSettingsProtocol(Protocol):
use_retry: bool
max_retry_attempt: int

View File

@@ -0,0 +1,21 @@
from t_tech.invest import Client
from t_tech.invest.retrying.settings_protocol import RetryClientSettingsProtocol
from t_tech.invest.retrying.sync.grpc_interceptor import RetryClientInterceptor
from t_tech.invest.retrying.sync.retry_manager import RetryManager
class RetryingClient(Client):
def __init__(
self,
token: str,
settings: RetryClientSettingsProtocol,
**kwargs,
):
self._retry_manager = RetryManager(settings=settings)
self._retry_interceptor = RetryClientInterceptor(
retry_manager=self._retry_manager
)
interceptors = kwargs.get("interceptors", [])
interceptors.append(self._retry_interceptor)
kwargs["interceptors"] = interceptors
super().__init__(token, **kwargs)

View File

@@ -0,0 +1,19 @@
import grpc
from t_tech.invest.retrying.sync.retry_manager import RetryManager
class RetryClientInterceptor(grpc.UnaryUnaryClientInterceptor):
def __init__(
self, retry_manager: RetryManager
): # pylint: disable=super-init-not-called
self._retry_manager = retry_manager
def _intercept_with_retry(self, continuation, client_call_details, request):
def call():
return continuation(client_call_details, request)
return self._retry_manager.call_with_retries(call=call)
def intercept_unary_unary(self, continuation, client_call_details, request):
return self._intercept_with_retry(continuation, client_call_details, request)

View File

@@ -0,0 +1,31 @@
import logging
import time
from typing import Any
from t_tech.invest.logging import get_metadata_from_call
from t_tech.invest.retrying.base_retry_manager import BaseRetryManager
logger = logging.getLogger(__name__)
class RetryManager(BaseRetryManager):
def call_with_retries(self, call: Any):
retries_left = self.get_initial_retries()
while retries_left > 0:
logger.debug("Trying to call")
result = call()
logger.debug("Call succeeded")
exception = result.exception()
if not exception:
return result
retries_left -= 1
logger.debug("Retries left = %s", retries_left)
metadata = get_metadata_from_call(exception)
seconds_to_sleep = self.extract_seconds_to_sleep(metadata)
self._sleep(seconds_to_sleep)
logger.debug("RetryManager exhausted, no retries left")
return result
def _sleep(self, seconds_to_sleep):
time.sleep(seconds_to_sleep)