Skip to content

Commit 1ebc9b6

Browse files
committed
fix: refactor
1 parent f19ed8d commit 1ebc9b6

File tree

2 files changed

+50
-29
lines changed

2 files changed

+50
-29
lines changed
Lines changed: 46 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,56 @@
1-
from datetime import datetime, timedelta
2-
import random
1+
import asyncio
2+
import math
3+
import time
34

45

5-
class ModelBreaker:
6+
class ModelBreaker(object):
67
def __init__(self):
78
# 初始化 allow_time 为当前时间
8-
self.allow_time = datetime.now()
9+
self._allow_time = time.perf_counter()
910

10-
def allow(self):
11-
# 检查当前时间是否在 allow_time 之后
12-
return datetime.now() > self.allow_time
11+
self._waiters = 0
12+
self._permits = 0
13+
self._base = 0
1314

14-
def reset(self, duration):
15-
# allow_time 重置为当前时间加上指定的持续时间
16-
self.allow_time = datetime.now() + timedelta(seconds=duration.total_seconds())
15+
def _allow(self) -> bool:
16+
# 检查当前时间是否在 allow_time 之后
17+
return time.perf_counter() > self._allow_time
1718

18-
def get_allowed_duration(self):
19+
def _get_allowed_duration(self) -> float:
1920
# 计算当前时间与 allow_time 之间的持续时间
20-
allow_duration = self.allow_time - datetime.now()
21+
allow_duration = self._allow_time - time.perf_counter()
22+
23+
# 如果持续时间为负,返回零
24+
if allow_duration < 0:
25+
return 0
26+
return allow_duration
27+
28+
def _acquire(self) -> int:
29+
self._waiters += 1
30+
return self._waiters
31+
32+
def _release(self) -> None:
33+
self._waiters -= 1
34+
self._permits += 1
35+
36+
def _jitter(self, i: int) -> float:
37+
if i <= self._base:
38+
return 0
39+
return math.log2(i - self._base)
40+
41+
def reset(self, duration: float) -> None:
42+
# 将 allow_time 重置为当前时间加上指定的持续时间
43+
self._allow_time = time.perf_counter() + duration
44+
self._base = self._permits
2145

22-
# 添加一个随机抖动,该抖动的范围为 0 到 10 秒,概率密度函数为 f(x) = x/50 (0 <= x <= 10)
23-
# 约有 1/100 的请求会在结束熔断的第一秒内发起重试
24-
jitter = timedelta(seconds=random.triangular(0, 10, 10))
46+
def wait(self) -> None:
47+
i = self._acquire()
48+
while not self._allow():
49+
time.sleep(self._get_allowed_duration() + self._jitter(i))
50+
self._release()
2551

26-
# 如果持续时间为负,则返回一个零时长的 timedelta 对象
27-
if allow_duration.total_seconds() < 0:
28-
return timedelta(0) + jitter
29-
return allow_duration + jitter
52+
async def asyncwait(self) -> None:
53+
i = self._acquire()
54+
while not self._allow():
55+
await asyncio.sleep(self._get_allowed_duration() + self._jitter(i))
56+
self._release()

volcenginesdkarkruntime/resources/batch_chat/completions.py

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -146,10 +146,7 @@ def create(
146146
last_time = self._get_request_last_time(timeout)
147147
model_breaker = self._client.get_model_breaker(model)
148148
while True:
149-
while not model_breaker.allow():
150-
if datetime.now() + timedelta(seconds=model_breaker.get_allowed_duration().total_seconds()) > last_time:
151-
raise ArkAPITimeoutError()
152-
time.sleep(model_breaker.get_allowed_duration().total_seconds())
149+
model_breaker.wait()
153150
if datetime.now() > last_time:
154151
raise ArkAPITimeoutError()
155152
try:
@@ -193,7 +190,7 @@ def create(
193190
except ArkAPIStatusError as err:
194191
retry_after = _get_retry_after(err.response)
195192
if retry_after is not None:
196-
model_breaker.reset(timedelta(seconds=retry_after))
193+
model_breaker.reset(retry_after)
197194
if _should_retry(err.response):
198195
continue
199196
else:
@@ -288,10 +285,7 @@ async def create(
288285
last_time = self._get_request_last_time(timeout)
289286
model_breaker = await self._client.get_model_breaker(model)
290287
while True:
291-
while not model_breaker.allow():
292-
if datetime.now() + timedelta(seconds=model_breaker.get_allowed_duration().total_seconds()) > last_time:
293-
raise ArkAPITimeoutError()
294-
await asyncio.sleep(model_breaker.get_allowed_duration().total_seconds())
288+
await model_breaker.asyncwait()
295289
if datetime.now() > last_time:
296290
raise ArkAPITimeoutError()
297291
try:
@@ -335,7 +329,7 @@ async def create(
335329
except ArkAPIStatusError as err:
336330
retry_after = _get_retry_after(err.response)
337331
if retry_after is not None:
338-
model_breaker.reset(timedelta(seconds=retry_after))
332+
model_breaker.reset(retry_after)
339333
if _should_retry(err.response):
340334
continue
341335
else:

0 commit comments

Comments
 (0)