# 문제상황
아마존 RDS 서비스로 MySQL 서버 인스턴스를 띄웠다. JPA의 entity 설정에서 LocalDateTime createAt을 @CreatedAt으로 설정해주었기 때문에 엔티티가 DB에 저장될 때 자동으로 DB 서버 시간에 맞춰 해당 필드에 시간을 넣어줄 것이다.
@Getter
@Setter
@EntityListeners(AuditingEntityListener.class) // for CreatedDate
@MappedSuperclass // jpa 상속된 jpa entity class -> 매핑 정보 전달
public class BaseEntity {
@CreatedDate
@Column(updatable = false)
private LocalDateTime createdAt;
@LastModifiedDate
@Column(updatable = false)
private LocalDateTime updatedAt;
}
그걸 기대하고 일기를 작성한 뒤 프로젝트 화면에 출력된 시간을 확인했다.
?? 9시간 과거로 타임리프 했다.
# 원인 규명
1) RDS 문제인가?
일단 RDS의 파라미터 그룹에서 time_zone이 Seoul/Asia인지 확인해야한다. 나같은 경우엔 DB 서버를 띄우자마자 time_zone을 바꿔줬기 때문에 괜찮았다. 만약 이를 고려하지 않았다면 RDS 서버 시간을 한국으로 수정하는 방법 링크를 걸어둘테니 참고하자.
아무튼 나는 똑바로 Asia/Seoul로 설정을 했단 말이지.
2) DB에 이상하게 저장된 것은 아닌지?
$ mysql -h {DB_URL} -u admin -p
접속해서 게시글 내용과 시간을 select했다.
DB에도 원하는 시간이 이상 없이 잘 넣어져있다.
남은건 JAVA appplication code이다. 프로젝트 코드를 직접 보는 수밖에 없다.
3) Service에서 데이터를 잘못 보내주었나?
일기의 DB 데이터를 가져오는 service 코드에 아래 log를 추가했다.
@Transactional
public FarmLogDto getFarmLogDetail(Long id) {
FarmLog foundFarmLog = getFarmLogById(id);
// 추가
log.info("현재 일기의 created_at : {}",foundFarmLog.getCreatedAt());
return FarmLogDto.fromEntity(foundFarmLog);
}
그럼 createdAt 필드가 콘솔 창에 찍힐 것이다.
같은 일기 페이지를 새로고침해서 로그를 확인했다.
이럴수가. 오전 8시 30분. 서비스에서까지 완벽했다. 이제 코드에서 남은것은 뷰 템플릿 밖에 없다.
4) view(thymeleaf) 문제인가?
html 코드에서, created_at을 보여주는 부분을 뽑아왔다.
<div th:text="${farmLog.createdAt+' 작성'}"></div>
여기도 이상이 없는데..
소스코드를 모두 뜯어보았지만 로그까지 잘 찍히는 마당에 무엇이 잘못되었는지 알 수가 없어서 localhost:8080 로컬서버를 띄워서 다시 한 번 확인했다.
엥? 왜 되지?
다시 한 번 배포한 프로젝트 사이트에서.
얜 왜 또 안돼?
DB 문제도 아니다. 프로젝트 소스코드 문제도 아니다. 남은건 배포 서버 뿐이다.
# Elastic Beanstalk 타임존 수정 -> 실패
프로젝트 배포를 위해 Elastic Beanstalk을 이용했는데, 여기서 문제가 일어난 듯 하다.
현재 나는 spring boot 프로젝트를 jar 패키징하여 사용하고 있고, 별다른 설정 없이 eb에서 기본으로 설정해주는 configuration으로 배포를 진행하고 있었다. 알아보니 배포된 웹 어플리케이션에서는 KST(한국시간)이 아닌 UTC(협정 세계시)를 사용하고 있었다. Elastic Beanstalk 서버에서 time 관련 객체를 불러오는 함수를 쓰면 자동으로 UTC 시간대로 변환이 되는 모양이다.
EB 서버 자체의 시간대를 바꾸거나, LocalDateTime 객체를 가져올 때 시간대를 지정해서 가져오는 등의 방법을 사용할 수 있을 것 같다.
그런데 내장 톰캣을 사용하는 spring boot의 특성상.. config 파일을 통해 서버 설정을 바꾸는 것은 쉽지 않아보였다. ebextensions/00-set-timezone.config 파일에 아래 커맨드를 입력한 후,
commands:
set_time_zone:
command: ln -f -s /usr/share/zoneinfo/Asia/Seoul /etc/localtime
jar 파일과 함께 압축해서 EB 서버에 다시 배포하면 된다는데.. 무슨 이유에선지 자꾸 실패했다. 서버 자체가 unhealthy 상황으로 열리지 않는 문제도 몇 번 발생했다. 열심히 찾아보니 java platfrom + JAR 패키징을 사용했을 때 Procfile도 새로 설정해야하고, 여타 신경쓸게 너무 많아서 😵💫 DevOps의 영역인 것 같아 해당 방법으로 문제를 해결하는 것은 포기했다.
# 임시 해결 ㅜ.ㅜ
어플리케이션의 코드 자체로 승부를 보겠다!!!
서버는 UTC를 기준으로 되어있다. LocalDateTime으로 DB의 time을 불러오면 자동으로 UTC 시간으로 parsing이 된다. KST가 UTC+9시간 이니까 배포된 어플리케이션은 -9시간이 된다는 소리다. 그래서 9시간 과거로 회귀한 것.
DB에서 받은 LocalDateTime 객체를 억지로 UTC화 시킨 후 다시 시간을 Asia/Seoul로 맞춰 바꾸는 코드를 작성하고 배포했다.
private static String createdAtString(LocalDateTime createdAt) {
return DateTimeFormatter.ofPattern("yyyy.MM.dd HH:mm")
.withZone(ZoneId.of("Asia/Seoul")).format(
createdAt.atZone(ZoneId.of("UTC")).toInstant());
}
그리고 결과.
대신.. 로컬에선 다시 답이 없어진다.
.ebextension을 건드리는 수밖에 없다..