결과값 통일의 장점

2024년 8월 19일 화요일

Today I Learned

날짜

2024년 8월 20일 화요일

내용

결과값의 통일

아임리포트 베타테스트가 성공하지 못했다. 시작하자마자 또 온갖 오류가 다터졌기 떄문… 가장 큰 문제는 매일 아침 실행되야할 정기 업데이트가 실행되지 않았다. 뜯어본 결과, 매일 아침 여러 광고 계정이 동일한 네이버 계정으로 API를 호출해서 요청이 실패한 걸로 추정된다. 그런데 이 서비스를 사용할 유저들의 대부분은 이런 형태(하나의 관리자 계정으로 여러 광고계정을 관리하는)일 것이라 이에 대한 대비가 필요하다. 점심먹다가, 다운로드받은 보고서 csv를 s3에 저장하는게 어떻냐는 아이디어를 들었는데 옳타구나 싶었다!

이 아이디어를 실현하기 전, 실패하는 원인이 확실히 요청 초과로 인한 것임을 파악해야 했다. 다양한 메서드, 함수들이 호출되는 상황에서 실패 사유를 저장하는 로직이 제대로 작동하지 않았다. 예를 들어,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
def function_B():
	try:
		...
		res = function_C()
		name = res["name"]
		...
		return True
	except Exception as e:
		logging.exception(str(e))
		import_log.status_reason = str(e)
		db.commit()
		return False
		
def function_C():
	try:
		...
		res = api_with_naver()
		if res.status_code == 200:
			return res.json()
		else:
			raise Exceiption(res.text)
	except Exception as e:
		logging.exceiption(str(e))
		return str(e)

이런 내부 호출되는 로직이 있다고 가정해보자. funcion_C()에서 어떤 오류가 발생했다. 너무 많은 요청이 네이버에 몰려 too many requests 를 반환받았다면? status_code가 429일테니 function_C() 는 “too many requests” 라는 문자열을 반환한다.

function_B() 입장에서는 function_C() 의 호출이 정상적으로 이루어졌다고 생각할 것. 일단 함수가 무사히 return 했으니까.. 원하는걸 뱉는지는 저 상황에선 알바가아니다. 그리고 다음 줄 name=res["name"] 이 호출되는 순간 예외가 발생한다. res가 dict가 아닌 string이기 떄문이다. 그럼 function B는 로그에 오류 메시지를 기록하는 except 문으로 빠진다. 그리고 res는 dict가 아니다, “name”이라는 attribute가 없다는 식으로 메시지를 남긴다. 그럼 나는 그걸 보고 “? 왜없어” 라고 생각하며 일일이 로그문을 추가하며 힘겹게 원인을 찾아 나아간다..

실제 에러는 function_C() 에서 발생했으니 그 메시지가 기록되야 한다. 그래서 다음과 같이 수정했다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
def function_B():
	try:
		...
		res = function_C()
		if res["result"] == False:
			raise Exception(res["detail"])
		name = res["name"]
		...
		return True
	except Exception as e:
		import_log.status_reason = str(e)
		db.commit()
		return False
		
def function_C():
	try:
		...
		res = api_with_naver()
		if res.status_code == 200:
			result = {
				"result": True,
				"detail": res.json(),
			}
			return result
		else:
			raise Exceiption(res.text)
	except Exception as e:
		result = {
			"result": False,
			"detail": str(e),
		}
		return result

이렇게 변경하면 function_C() 가 뱉어낸 에러 메시지가 그대로 반영되니 “아 네이버 api에서 문제였구만” 이 바로 성립된다. 앞으로 개발할 때도 항상 반환형태를 통일해야겠다.

회고

근데 정기 업데이트는 언제고치지