클라이언트 체크인 전에 작은 스크립트를 돌려서 각 클라이언트 사이트를 세 가지 지표로 점수를 매기는데, 클라이언트별 가중치는 해당 클라이언트의 analytics 엔드포인트에서 가져와요. 가져오는 부분은 return_exceptions=True를 준 asyncio.gather로 하고 있어서, 클라이언트 하나가 망가져도 나머지가 취소되지 않아야 하는 거죠? fetch_weights는 응답이 비어 있으면 ValueError를 raise하고, 저는 gather를 try/except ValueError로 감싸서 경고를 로그로 남기고 기본 가중치로 대체하도록 했어요.
첫 번째 클라이언트는 점수가 출력되는데, 응답이 빈 eastside-cycles에서 스크립트가 죽어요. "falling back to defaults" 경고는 아예 안 나와요. except Exception으로 바꿔 보고 python3 -X dev main.py로도 돌려 봤는데, 둘 다 달라진 게 없어요.
이해가 안 되는 건, ValueError는 분명히 fetch_weights에서 raise되는데 TypeError가 ValueError 객체를 언급한다는 거예요.
juniper-florals: 83.0
Traceback (most recent call last):
File "main.py", line 59, in <module>
main()
File "main.py", line 55, in main
asyncio.run(score_all(clients))
...
File "main.py", line 40, in score_all
value = score(client["metrics"], weights)
File "main.py", line 26, in score
return round(sum(metrics[k] * weights[k] for k in weights), 1)
TypeError: 'ValueError' object is not iterable
main.py의 관련 부분이에요:
async def score_all(clients):
try:
all_weights = await asyncio.gather(
*(fetch_weights(c) for c in clients),
return_exceptions=True,
)
except ValueError:
log.warning("weights fetch failed, falling back to defaults")
all_weights = [DEFAULT_WEIGHTS for _ in clients]
for client, weights in zip(clients, all_weights):
value = score(client["metrics"], weights)
print(client["slug"] + ": " + str(value))
왜 핸들러가 건너뛰어지는 걸까요?
영어에서 번역·원문 보기I run a small script before client check-ins that scores each client's site from three metrics, with per-client weights fetched from their analytics endpoint. The fetches go through asyncio.gather with return_exceptions=True, so one broken client doesn't cancel the rest, right? fetch_weights raises ValueError when the response is empty, and I wrapped the gather in try/except ValueError to log a warning and fall back to the default weights.
The first client prints a score, then the script dies on eastside-cycles, which has an empty response. There's no "falling back to defaults" warning at all. I changed it to except Exception, and I ran it with python3 -X dev main.py, and neither changed anything.
The part I don't get is that the TypeError mentions a ValueError object, even though the ValueError is clearly raised in fetch_weights.
juniper-florals: 83.0
Traceback (most recent call last):
File "main.py", line 59, in <module>
main()
File "main.py", line 55, in main
asyncio.run(score_all(clients))
...
File "main.py", line 40, in score_all
value = score(client["metrics"], weights)
File "main.py", line 26, in score
return round(sum(metrics[k] * weights[k] for k in weights), 1)
TypeError: 'ValueError' object is not iterable
The relevant part of main.py:
async def score_all(clients):
try:
all_weights = await asyncio.gather(
*(fetch_weights(c) for c in clients),
return_exceptions=True,
)
except ValueError:
log.warning("weights fetch failed, falling back to defaults")
all_weights = [DEFAULT_WEIGHTS for _ in clients]
for client, weights in zip(clients, all_weights):
value = score(client["metrics"], weights)
print(client["slug"] + ": " + str(value))
Why is the handler skipped?