diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index 089ed48..c2eb9cd 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -85,43 +85,40 @@ jobs: - name: Restart backend via SSH env: DEPLOY_KEY: ${{ secrets.DEPLOY_SSH_KEY }} + DEPLOY_HOST: 192.168.1.20 run: | mkdir -p ~/.ssh - echo "$DEPLOY_KEY" > ~/.ssh/id_deploy + printf '%s\n' "$DEPLOY_KEY" > ~/.ssh/id_deploy chmod 600 ~/.ssh/id_deploy - # Docker 컨테이너 → 호스트: bridge gateway(172.17.0.1) 경유 - DOCKER_HOST_IP=172.17.0.1 - ssh-keyscan $DOCKER_HOST_IP >> ~/.ssh/known_hosts 2>/dev/null || true + ssh-keyscan -T 5 $DEPLOY_HOST >> ~/.ssh/known_hosts 2>/dev/null || true - SSH_CMD="ssh -i ~/.ssh/id_deploy -o StrictHostKeyChecking=no root@$DOCKER_HOST_IP" + SSH_CMD="ssh -i ~/.ssh/id_deploy -o StrictHostKeyChecking=no -o ConnectTimeout=10 root@$DEPLOY_HOST" $SSH_CMD bash -s << 'RESTART' - set -e DEPLOY_DIR=/devdata/services/kcg/backend SYSTEMD_DIR=/etc/systemd/system # systemd 서비스 파일 갱신 - CHANGED=0 if [ -f "$DEPLOY_DIR/kcg-backend.service" ] && ! diff -q "$DEPLOY_DIR/kcg-backend.service" "$SYSTEMD_DIR/kcg-backend.service" >/dev/null 2>&1; then cp "$DEPLOY_DIR/kcg-backend.service" "$SYSTEMD_DIR/kcg-backend.service" - CHANGED=1 + systemctl daemon-reload fi - [ "$CHANGED" = "1" ] && systemctl daemon-reload # 백엔드 재시작 echo "--- Restarting kcg-backend ---" systemctl restart kcg-backend - # 기동 확인 (최대 30초) - for i in $(seq 1 30); do - if curl -sf http://localhost:8080/api/aircraft > /dev/null 2>&1; then - echo "Backend started successfully (${i}s)" + # 기동 확인 (최대 60초) + for i in $(seq 1 60); do + HTTP=$(curl -s -o /dev/null -w '%{http_code}' http://localhost:8080/api/aircraft 2>/dev/null || echo "000") + if [ "$HTTP" = "200" ] || [ "$HTTP" = "401" ] || [ "$HTTP" = "403" ]; then + echo "Backend started successfully (${i}s, HTTP $HTTP)" exit 0 fi sleep 1 done - echo "WARNING: Startup timeout. Recent logs:" - journalctl -u kcg-backend --no-pager -n 20 + echo "WARNING: Startup timeout" + journalctl -u kcg-backend --no-pager -n 10 exit 1 RESTART diff --git a/backend/src/main/java/gc/mda/kcg/collector/sensor/PressureCollector.java b/backend/src/main/java/gc/mda/kcg/collector/sensor/PressureCollector.java index cb27cff..a95e121 100644 --- a/backend/src/main/java/gc/mda/kcg/collector/sensor/PressureCollector.java +++ b/backend/src/main/java/gc/mda/kcg/collector/sensor/PressureCollector.java @@ -91,19 +91,16 @@ public class PressureCollector { try { // Open-Meteo 시간 형식: "2026-03-18T07:00" (Z 없음) → Z 추가 Instant readingTime = OffsetDateTime.parse(timeStr + "Z").toInstant(); - try { - repository.save(PressureReading.builder() - .station(station) - .lat(lat) - .lng(lng) - .pressureHpa(pressure) - .readingTime(readingTime) - .collectedAt(now) - .build()); - saved++; - } catch (Exception ignored) { - // unique constraint violation = 이미 존재, 무시 - } + if (repository.existsByStationAndReadingTime(station, readingTime)) continue; + repository.save(PressureReading.builder() + .station(station) + .lat(lat) + .lng(lng) + .pressureHpa(pressure) + .readingTime(readingTime) + .collectedAt(now) + .build()); + saved++; } catch (DateTimeParseException e) { log.debug("기압 시간 파싱 실패: {}", timeStr); } diff --git a/backend/src/main/java/gc/mda/kcg/domain/sensor/PressureReadingRepository.java b/backend/src/main/java/gc/mda/kcg/domain/sensor/PressureReadingRepository.java index 3c418c0..d6057d4 100644 --- a/backend/src/main/java/gc/mda/kcg/domain/sensor/PressureReadingRepository.java +++ b/backend/src/main/java/gc/mda/kcg/domain/sensor/PressureReadingRepository.java @@ -6,6 +6,7 @@ import java.time.Instant; import java.util.List; public interface PressureReadingRepository extends JpaRepository { + boolean existsByStationAndReadingTime(String station, Instant readingTime); List findByStationAndReadingTimeAfterOrderByReadingTimeAsc(String station, Instant since); List findByReadingTimeAfterOrderByReadingTimeAsc(Instant since); }