@@ -45,9 +45,7 @@ public class KopisApiService {
4545
4646 private final ConcertImageRepository imageRepository ;
4747
48- private final ConcertUpdateTimeRepository concertUpdateTimeRepository ;
49-
50- private final ConcertKopisApiLogRepository concertKopisApiLogRepository ;
48+ private final ConcertKopisApiLogService concertKopisApiLogService ;
5149
5250 private final ConcertRedisRepository concertRedisRepository ;
5351
@@ -59,24 +57,20 @@ public class KopisApiService {
5957
6058 private final RestClient restClient ;
6159
62- private int savedIndex ;
63-
6460 public KopisApiService (
6561 ConcertRepository concertRepository ,
6662 ConcertPlaceRepository placeRepository ,
6763 TicketOfficeRepository ticketOfficeRepository ,
6864 ConcertImageRepository imageRepository ,
69- ConcertUpdateTimeRepository concertUpdateTimeRepository ,
7065 ConcertRedisRepository concertRedisRepository ,
71- ConcertKopisApiLogRepository concertKopisApiLogRepository
66+ ConcertKopisApiLogService kopisApiLogService
7267 ) {
7368 this .concertRepository = concertRepository ;
7469 this .placeRepository = placeRepository ;
7570 this .ticketOfficeRepository = ticketOfficeRepository ;
7671 this .imageRepository = imageRepository ;
77- this .concertUpdateTimeRepository = concertUpdateTimeRepository ;
7872 this .concertRedisRepository = concertRedisRepository ;
79- this .concertKopisApiLogRepository = concertKopisApiLogRepository ;
73+ this .concertKopisApiLogService = kopisApiLogService ;
8074 this .restClient = RestClient .builder ()
8175 .baseUrl ("https://kopis.or.kr/openApi/restful" )
8276 .defaultHeader (HttpHeaders .CONTENT_TYPE , MediaType .APPLICATION_XML_VALUE )
@@ -88,12 +82,12 @@ public KopisApiService(
8882 @ Transactional
8983 public void setConcertsList () throws InterruptedException {
9084 // 최초 시작 시간 저장
91- if (concertUpdateTimeRepository . count () != 0 ) {
85+ if (concertKopisApiLogService . isInitComplete () ) {
9286 log .error ("이미 최초 저장이 되었습니다!. UpdateConcert를 통해 데이터를 갱신해주십시오!" );
9387 return ;
9488 }
95- String key = "init" ;
9689
90+ String key = "kopis_lock" ;
9791 String value = concertRedisRepository .lockGet (key );
9892 if (value != null ) {
9993 log .error ("이미 실행중인 스레드입니다." );
@@ -102,6 +96,8 @@ public void setConcertsList() throws InterruptedException {
10296 concertRedisRepository .lockSave (key ,"running..." );
10397 }
10498
99+ // 시작 시간
100+ concertKopisApiLogService .saveStartLog ("save" ,"공연 데이터 초기 저장 시작" ,0L );
105101 LocalDateTime now = LocalDateTime .now ();
106102 long startNs = System .currentTimeMillis ();
107103
@@ -116,22 +112,16 @@ public void setConcertsList() throws InterruptedException {
116112 int addedConcertImages = 0 ;
117113
118114 int page = 1 ;
119- try {
115+
116+ // 이전 실패가 있으면 실패 시점에서 다시 시도 아니면 0 에서 시작
117+ Long index = concertKopisApiLogService .getLastSaveFailIndex ();
118+ try {
120119 // 모든 공연을 가져오기
121120 totalConcertsList = getAllConcertsListFromKopisAPI (page );
122- }catch (Exception e ){
123- log .error ("공연 목록 저장 도중 오류 발생" );
124- log .error ("오류 내용 : " + e .getMessage ());
125- return ;
126- } finally {
127- concertRedisRepository .unlockSave (key );
128- }
121+ log .info ("저장할 총 공연의 수: {}" , totalConcertsList .size ());
122+ log .info ("공연 목록 로드 완료, 공연 세부 내용 로드 및 저장" );
129123
130- concertRedisRepository .lockSave (key ,"running..." );
131- log .info ("저장할 총 공연의 수: {}" , totalConcertsList .size ());
132- log .info ("공연 목록 로드 완료, 공연 세부 내용 로드 및 저장" );
133- try {
134- for (int i = savedIndex ; i < totalConcertsList .size (); i ++) {
124+ for (int i = index .intValue (); i < totalConcertsList .size (); i ++) {
135125 ConcertListElement concertListElement = totalConcertsList .get (i );
136126 // API에서 공연 상세 가져오기
137127 ConcertDetailResponse concertDetailResponse = getConcertDetailResponse (serviceKey , concertListElement .getApiConcertId ());
@@ -143,7 +133,6 @@ public void setConcertsList() throws InterruptedException {
143133 String concertPlaceAPiKey = concertDetailResponse .getConcertDetail ().getMt10id ();
144134 // 캐시로 사용하는 맵이나 DB에서 콘서트 위치가 있는지 확인하기 -> 없으면 저장
145135 ConcertPlace concertPlace = getConcertPlaceOrSaveNewConcertPlace (concertPlaceMap , concertPlaceAPiKey );
146-
147136 addedConcertPlaces = concertPlaceMap .size ();
148137 // 공연 저장
149138 Concert savedConcert = saveConcert (concertPlace , concertDetail );
@@ -153,37 +142,38 @@ public void setConcertsList() throws InterruptedException {
153142 addedConcertImages += saveConcertImages (concertDetail , savedConcert );
154143
155144 addedConcerts ++;
156- savedIndex ++;
145+ index ++;
157146 }
147+
148+ concertKopisApiLogService .saveSuccessLog ("save" ,"공연 데이터 초기 저장 완료" ,0L );
149+ log .info (now + "시 기준 " + totalConcertsList .size () + "개의 공연 데이터 저장 완료!" );
150+ long endNs = System .currentTimeMillis ();
151+ long durationSec = ((endNs - startNs ) / 1000 );
152+ log .info (durationSec /60 + "분, " + durationSec % 60 + "초 소요되었습니다." );
153+ cacheClear ();
158154 } catch (Exception e ) {
159155 log .error ("개별 공연 세부 내용 저장 도중 오류 발생" );
160156 log .error ("오류 내용 : " + e .getMessage ());
161- e .printStackTrace ();
162- return ;
157+ concertKopisApiLogService .saveErrorLog ("save" ,e ,index );
163158 } finally {
164159 concertRedisRepository .unlockSave (key );
165160 }
166- ConcertUpdateTime concertUpdateTime = new ConcertUpdateTime (now );
167- concertUpdateTimeRepository .save (concertUpdateTime );
168- savedIndex = 0 ;
169- log .info (now + "시 기준 " + totalConcertsList .size () + "개의 공연 데이터 저장 완료!" );
170- long endNs = System .currentTimeMillis ();
171- long durationSec = ((endNs - startNs ) / 1000 );
172- log .info (durationSec /60 + "분, " + durationSec % 60 + "초 소요되었습니다." );
173161 }
174162
175163 @ Transactional
176164 public SetResultResponse updateConcertData () throws InterruptedException {
177- String key = "init " ;
165+ String key = "kopis_lock " ;
178166 String value = concertRedisRepository .lockGet (key );
179167 if (value != null ) {
180- log .error ("초기 업데이트가 진행중입니다 ." );
168+ log .error ("락이 걸린 작업입니다 ." );
181169 return null ;
170+ } else {
171+ concertRedisRepository .lockSave (key ,"running..." );
182172 }
183173
184- ConcertUpdateTime concertUpdateTime = concertUpdateTimeRepository . getReferenceById ( 1L );
185- LocalDate lastUpdatedDate = concertUpdateTime . getUpdateTime ().toLocalDate ();
186- ConcertUpdateTime updatedTime = concertUpdateTime . setUpdateTime ( LocalDateTime . now () );
174+
175+ LocalDate lastUpdatedDate = concertKopisApiLogService . getLastSaveTime ().toLocalDate ();
176+ concertKopisApiLogService . saveStartLog ( "save" , "공연 데이터 업데이트 시작" , 0L );
187177 LocalDate sdate = lastUpdatedDate ;
188178 LocalDate edate = LocalDate .now ().plusYears (1 );
189179
@@ -213,8 +203,7 @@ public SetResultResponse updateConcertData() throws InterruptedException {
213203 }
214204 log .info ("공연 목록 로드 완료, 공연 세부 내용 로드 및 저장" );
215205
216- savedIndex = 0 ;
217- for (int i = savedIndex ; i < totalConcertsList .size (); i ++) {}
206+ for (int i = 0 ; i < totalConcertsList .size (); i ++) {}
218207 for (ConcertListElement performanceListElement : totalConcertsList ) {
219208 ConcertDetailResponse concertDetailResponse = getConcertDetailResponse (serviceKey , performanceListElement .getApiConcertId ());
220209 ConcertDetailElement concertDetail = concertDetailResponse .getConcertDetail ();
@@ -250,15 +239,17 @@ public SetResultResponse updateConcertData() throws InterruptedException {
250239 Thread .sleep (300 );
251240 }
252241
253- // 갱신 후 업데이트 시간 저장, 캐시의 데이터 삭제
254- concertUpdateTimeRepository .save (updatedTime );
255- concertRedisRepository .deleteAllConcertsList ();
256- concertRedisRepository .deleteAllCachedConcertDetail ();
257- concertRedisRepository .deleteTotalConcertsCount (ListSort .VIEW );
242+ // 갱신 후 업데이트 시간 저장
243+ concertKopisApiLogService .saveSuccessLog ("save" ,"공연 데이터 업데이트 완료" ,0L );
244+ // 락 해제
245+ concertRedisRepository .unlockSave (key );
246+ // 이전 캐시 데이터 삭제
247+ cacheClear ();
258248 return new SetResultResponse (addedConcerts ,updatedConcerts ,addedConcertPlaces ,updatedConcertPlaces ,addedConcertImages ,updatedConcertImages ,addedTicketOffices ,updatedTicketOffices );
259249 }
260250
261251
252+
262253 @ Transactional
263254 public void concertUpdateByKopisApi (Long concertId ){
264255 // 해당 콘서트 ID로 콘서트 객체 찾기
@@ -388,6 +379,13 @@ private int saveConcertImages(ConcertDetailElement concertDetail, Concert savedC
388379 return concertDetail .getConcertImageUrls ().size ();
389380 }
390381
382+ // 캐시를 초기화합니다.
383+ private void cacheClear () {
384+ concertRedisRepository .deleteAllConcertsList ();
385+ concertRedisRepository .deleteAllCachedConcertDetail ();
386+ concertRedisRepository .deleteTotalConcertsCount (ListSort .VIEW );
387+ }
388+
391389 public ConcertListResponse getConcertsList () {
392390 return getConcertListResponse (serviceKey , sdate , edate , 1 );
393391 }
0 commit comments