Cloud Function 에러 및 재시도

Caesars·2022년 9월 25일
1

GCP 도입

목록 보기
4/8

Cloud Function 에러 발생


Pub/Sub 에서 받아온 데이터를 Cloud Function에서 처리 후에 여러 BigQuery 테이블에 삽입하는 아키텍처를 구축했습니다. 하지만 Cloud Function 내에서 드물게 BigQueryException이 발생하고 있었습니다. GCF 가이드 에 따르면 드문 경우지만 내부 오류로 함수가 조기 종료된다고 합니다. BigQueryException.class의 isRetryble() 메소드로 GCF 내부 에러인지 아니면 사용자 에러 인지 판별이 가능합니다.

데이터 삽입 성공 여부

에러가 발생시 빅쿼리에 데이터가 삽입되는 경우도 있고 그렇지 않은 경우도 있었습니다. BigQueryException 메시지 종류에 따라 데이터 삽입이 결정되는지 확인해보았으나 에러 메시지 종류와는 무관하다고 판단했습니다. 같은 메시지인데도 데이터가 삽입된 경우가 있고 삽입되지 않은 경우도 있었습니다.

BigQueryException 메시지 종류

클래스는 하나지만 에러 메시지는 다양합니다.

  • The service is currently unavailable.
  • An internal error occurred and the request could not be completed.
  • Deadline exceeded.
  • Connection to server broken.
  • read time out.
  • connection reset.
  • Unexpected end of file from server.
  • 502 Bad Gateway POST.

개선 사항

Cloud Function 재시도 설정

Cloud Funtion 탭에서 재시도 옵션 설정이 가능합니다. 만약 function 내부 에러라면 에러를 catch하지 않고 throw. 자동적으로 이벤트를 재시도 합니다. 다만 동일한 이벤트를 무한히 호출할 가능성이 있으므로 발생한 지 60초가 넘은 이벤트는 중단하도록 코드를 수정했습니다.

데이터 삽입시 InsertId 를 설정하여 삽입

또한 데이터 삽입시 InsertId 설정을 추가했습니다. 처음에는 function 내부 에러인 경우 재시도를 해야겠다고 생각했지만 에러가 발생했는데도 데이터가 정상적으로 삽입된 경우도 있습니다. 이 경우 function을 재시도 할 경우 데이터가 중복으로 쌓이게 됩니다. 따라서 insertId 를 설정해 중복 데이터 삽입을 방지했습니다.
동일한 InsertID 에 한해서는 해당 테이블에 60초 동안 한 건만 삽입되도록 BigQuery가 보장합니다. InsertId 는 데이터의 필드를 조합하여 다른 데이터와 겹치지 않는 unique 값을 갖도록 구성했습니다.

코드


ZonedDateTime utcNow = ZonedDateTime.now(ZoneOffset.UTC);
ZonedDateTime timestamp = ZonedDateTime.parse(context.timestamp());

long eventAge = Duration.between(timestamp, utcNow).toMillis();

// 무한히 재시도 할 수 있으므로 최초 시점으로부터 일정 시간이 지난 이벤트는 무시
if (eventAge > MAX_EVENT_AGE) {		
    logger.severe("Insert operation stoped due to eventAge \n" + new String(Base64.getDecoder().decode(message.data)));
    return;
}

/*
 	이벤트 전처리
*/

try {
    InsertAllResponse response = bigQuery.insertAll(InsertAllRequest
        .newBuilder(TableId.of(Constants.DataSet.DATASET_NAME, tableName))
        .addRow(insertId, rowContent)
        .build());
    } catch (BigQueryException e) {
    	logger.severe("Insert operation not performed \n" + e.toString());
            
        // Cloud Function 내부에러 재시도
        if (e.isRetryable()) {
          	throw e;
        }
    }

참고

https://cloud.google.com/functions/docs/bestpractices/retries?hl=ko
https://cloud.google.com/functions/docs/samples/functions-tips-infinite-retries?hl=ko#functions_tips_infinite_retries-java

profile
잊기전에 저장

0개의 댓글