跳到主要内容

异常和重试机制

异常

ClientException

ClientException代表明确的客户端错误,比如以下错误码:

错误码原因
SDK.SDK_INVALID_PARAMETER使用了非法的参数值,请求尚未发送到服务端之前,被检测到错误
SDK.SDK_ENDPOINT_RESOLVING_ERROR找不到合适的Endpoint,无法把请求发送到服务端
SDK.SDK_INVALID_REQUEST使用了框架无法处理的Request对象

ServerException

在HTTP API的使用过程中,对于status_code != 200的请求结果,服务端会提供明确的error_code作为错误码。这些失败或者错误的请求,SDK会通过ServerException来表示。

ServerException的错误码和原因,请参考HTTP API的服务端文档。

重试机制

不同的业务场景,需要的重试策略很可能不一致,SDK预置了重试策略,也允许自定义扩展和设置。

HTTP API

默认机制

  1. 默认不重试
  2. 设置了重试次数后,符合条件的请求会重试,不符合条件的请求不会重试,开启重试的代码示例如下:
from webullsdkcore.client import ApiClient

# 设置最大重试次数为3
client = ApiClient(app_key="<your_app_key>", app_secret="<your_app_secret>", region_id="<region_id>", auto_retry=True,
max_retry_num=3)

默认重试的条件判断说明:

  1. 超过最大重试次数,不重试
  2. 不是GET请求,不重试
  3. 客户端IOError会重试,非特定的ClientException不重试
  4. 服务端的特定错误码(如下)重试,非特定错误码不重试
    • TOO_MANY_REQUESTS
    • SERVICE_NOT_AVAILABLE
    • GATEWAY_TIMEOUT
    • INTERNAL_ERROR
  5. 其他错误和异常,不重试

行情订阅

默认机制

  1. 默认符合条件的请求会重试,不符合条件的请求不会重试,重试的次数没有限制,重试的时间间隔为10秒,自定义重试的代码示例如下:
from webullsdkmdata.quotes.subscribe.default_client import DefaultQuotesClient
from webullsdkcore.retry.retry_policy import NO_RETRY_POLICY

# 设置不重试
quotes_client = DefaultQuotesClient("<your_app_key>", "<your_app_secret>", "<region_id>", retry_policy=NO_RETRY_POLICY)

默认重试的条件判断说明:

  1. 客户端IOError会重试,非特定的ClientException不重试
  2. mqtt协议的特定错误码(如下)重试,非特定错误码不重试
    • 3 (Server Unavailable)
    • 5 (Authorization error)
  3. 其他错误和异常,重试

交易事件订阅/行情API

默认机制

  1. 默认符合条件的请求会重试,不符合条件的请求不会重试,重试的次数没有限制,重试的时间间隔为5秒,自定义重试的代码示例如下:
from webullsdktradeeventscore.events_client import EventsClient
from webullsdkcore.retry.retry_policy import NO_RETRY_POLICY

# 设置不重试
client = EventsClient("<your_app_key>", "<your_app_secret>", "<region_id>", retry_policy=NO_RETRY_POLICY)

默认重试的条件判断说明:

  1. gRPC协议的特定错误码(如下)重试,非特定错误码不重试
    • 2 (UNKNOWN)
    • 13 (INTERNAL)
    • 14 (UNAVAILABLE)
  2. 其他错误和异常,不重试

自定义重试策略

自定义重试策略,主要通过扩展RetryPolicy来实现

RetryPolicy通过RetryCondition实现是否重试的条件判断, 通过BackoffStrategy实现重试时间间隔的退避策略

以下代码演示了RetryOnRcCodeCondition的实现:

# 根据MQTT协议的错误码, 实现的RetryCondition
class RetryOnRcCodeCondition(RetryCondition):
DEFAULT_RETRYABLE_RC_CODE_LIST = [
3,
5,
]

def __init__(self, retryable_rc_code_list=None):
if retryable_rc_code_list:
self.retryable_rc_code_list = retryable_rc_code_list
else:
self.retryable_rc_code_list = self.DEFAULT_RETRYABLE_RC_CODE_LIST

def should_retry(self, retry_policy_context):
if retry_policy_context.rc_code in self.retryable_rc_code_list:
return RetryCondition.RETRY
else:
return RetryCondition.NO_RETRY

以下代码演示了ExponentialBackoffStrategy的实现

# 一个简单的指数退避策略
class ExponentialBackoffStrategy(BackoffStrategy):
MAX_RETRY_LIMIT = 30

def __init__(self, base_delay_in_milliseconds, max_delay_in_milliseconds):
self.base_delay_in_milliseconds = base_delay_in_milliseconds
self.max_delay_in_milliseconds = max_delay_in_milliseconds

def compute_delay_before_next_retry(self, retry_policy_context):
retries = min(self.MAX_RETRY_LIMIT, retry_policy_context.retries_attempted)
delay = min(self.max_delay_in_milliseconds, self.base_delay_in_milliseconds << retries)
return delay

以下代码演示了一个简单的RetryPolicy实现:

class MyRetryPolicy(RetryPolicy):
def __init__(self):
RetryPolicy.__init__(self, RetryOnRcCodeCondition(), ExponentialBackoffStrategy())