Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ feat(batch): recommend music based on real time weather #472

Draft
wants to merge 2 commits into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions backend/streetdrop-batch/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,18 @@ jar {
enabled = false
}

ext {
set('springCloudVersion', "2022.0.3")
}

dependencies {
implementation project(':streetdrop-domain')
implementation project(':streetdrop-common')
implementation 'org.springframework.boot:spring-boot-starter-batch'
implementation 'org.springframework.boot:spring-boot-starter-quartz'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.cloud:spring-cloud-starter-openfeign'

runtimeOnly 'com.mysql:mysql-connector-j'

Expand All @@ -34,6 +39,12 @@ dependencies {
testAnnotationProcessor 'org.projectlombok:lombok'
}

dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
}
}

test {
useJUnitPlatform()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.depromeet.config;

import com.depromeet.external.feign.client.OpenApiFeignClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableFeignClients(clients = OpenApiFeignClient.class)
public class FeignConfig {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.depromeet.domains.weather.jobs;

import com.depromeet.domains.weather.service.WeatherService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

@Component
@RequiredArgsConstructor
public class RealTimeWeatherJob {

private final WeatherService weatherService;

public void run() {
weatherService.getRealTimeWeather();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.depromeet.domains.weather.response.dto;

public record BodyDto(
String dataType,
ItemsDto items,
int pageNo,
int numOfRows,
int totalCount
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.depromeet.domains.weather.response.dto;

public record HeaderDto(
String resultCode,
String resultMsg
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.depromeet.domains.weather.response.dto;

public record ItemDto(
String baseDate,
String baseTime,
String category,
int nx,
int ny,
String obsrValue
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.depromeet.domains.weather.response.dto;

import java.util.List;

public record ItemsDto(
List<ItemDto> item
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.depromeet.domains.weather.response.dto;

public record ResponseDto(
HeaderDto header,
BodyDto body
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.depromeet.domains.weather.response.dto;

public record WeatherResponseDto(
ResponseDto response
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.depromeet.domains.weather.scheduler;

import com.depromeet.domains.weather.jobs.RealTimeWeatherJob;
import lombok.RequiredArgsConstructor;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
@RequiredArgsConstructor
public class RealTimeWeatherBatchScheduler {

private final RealTimeWeatherJob realTimeWeatherJob;

@Scheduled(cron = "0 0 */3 * * *")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

소스코드에 cron 시간을 설정하면 나중에 시간을 변경하고 싶을때 소스코드 변경 및 애플리케이션 재배포가
필요해서 rundeck 같은 오픈소스나 aws event trigger 같은 거 다같이 논의해서 써보면 어떨까여? 👍

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

외부에서 변경을 할 수 있군요 👀
안건 올려두겠습니다. 다음 회의 때 논의해 보아요!

public void runWeatherJob() {
realTimeWeatherJob.run();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.depromeet.domains.weather.service;

import com.depromeet.external.feign.client.OpenApiFeignClient;
import com.depromeet.domains.weather.response.dto.WeatherResponseDto;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class WeatherService {

@Value("${open-api.secret-key}")
private String openApiKey;

private final OpenApiFeignClient openApiFeignClient;

public WeatherResponseDto getRealTimeWeather() {
String date = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
String time = LocalTime.now().format(DateTimeFormatter.ofPattern("HHmm"));

return openApiFeignClient.getRealTimeWeather(openApiKey, 1, 8, "json", date, time, 60, 125);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.depromeet.external.feign.client;

import com.depromeet.config.FeignConfig;
import com.depromeet.domains.weather.response.dto.WeatherResponseDto;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

@FeignClient(name = "openApiFeignClient", url = "${open-api.base-url}", configuration = FeignConfig.class)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오 MVC나 Webflux가 아니라 Feign을 쓰신 이유가 있으신지 궁금합니다! 👍

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

외부 API와 통신하는 방법으로 5가지 정도 고민했어요.

  • RestTemplate, WebClient, RestClient, HttpInterface, OpenFeign

성능을 결정하는 요인은 외부 API의 속도라고 생각해서 어떤 기술을 쓰든 성능은 비슷할 것이라 생각했어요.
가장 기술적으로 도전적이고, 경험해 보지 않은 기술이며, 코드 상으로 가독성 있고, 확장성 있는 기술을 채택하고 싶었습니다.
그 중 OpenFeign이 어노테이션 기반으로 가독성 있게 작성할 수 있어서 마음에 들었고, interface 형식으로 작성하기 때문에 확장성도 좋다고 느껴서 채택했습니다!

public interface OpenApiFeignClient {

@GetMapping(value = "${open-api.weather-api-url}", produces = MediaType.APPLICATION_JSON_VALUE)
WeatherResponseDto getRealTimeWeather(
@RequestParam("serviceKey") String serviceKey,
@RequestParam("pageNo") int pageNo,
@RequestParam("numOfRows") int numOfRows,
@RequestParam("dataType") String dataType,
@RequestParam("base_date") String baseDate,
@RequestParam("base_time") String baseTime,
@RequestParam("nx") int nx,
@RequestParam("ny") int ny);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

파라미터가 많아서 @RequestParam보다는 객체나 @RequestBody로 받는 것은 어떨까요? 😄

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Open API로 요청을 보내는 부분이에요!
정해진 규칙대로 사용해야 해서 수정은 불가능 할 것 같습니다.


}
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,8 @@ auth:
header: ${AUTH_HEADER}
secret-key: ${AUTH_SECRET_KEY}
fcm:
value: streetdrop-notification-fcm.json
value: streetdrop-notification-fcm.json
open-api:
secret-key: ${OPEN_API_SECRET_KEY}
base-url: ${OPEN_API_BASE_URL}
weather-api-url: ${WEATHER_API_URL}