UserSpend 코드
@Getter
@AllArgsConstructor
public class UserSpend {
@Getter
private Long userId;
private int totalBookPriceSum;
private int totalDiscountAmountSum;
public UserSpend() {
}
public UserSpend(Long userId, Long totalBookPriceSum, Long totalDiscountAmountSum) {
this.userId = userId;
this.totalBookPriceSum = totalBookPriceSum.intValue();
this.totalDiscountAmountSum = totalDiscountAmountSum.intValue();
}
public int getActualSpent() {
return totalBookPriceSum - totalDiscountAmountSum;
}
}
- 생성자 중복 정의
- Getter 중복 정의
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class UserSpend {
private Long userId;
private int totalBookPriceSum;
private int totalDiscountAmountSum;
public int getActualSpent() {
return totalBookPriceSum - totalDiscountAmountSum;
}
}
yml
spring:
application:
name: batchservice
lifecycle:
timeout-per-shutdown-phase: 30s
cloud:
discovery:
enabled: false
config:
enabled: false
dbcp2:
datasource:
url: jdbc:h2:mem:testdb
driver-class-name: org.h2.Driver
username: sa
password: ""
initial-size: 5
max-total: 5
max-idle: 5
min-idle: 5
server:
port: 10396
shutdown: graceful
eureka:
client:
enabled: false
# Order Payment
order:
api:
url: http://localhost:10392
# Book
book:
api:
url: http://localhost:10390
# Coupon
coupon:
api:
url: http://localhost:10388
안쓰는 것들 삭제
spring:
application:
name: batchservice
lifecycle:
timeout-per-shutdown-phase: 30s
cloud:
discovery:
enabled: false
config:
enabled: false
dbcp2:
datasource:
url: jdbc:h2:mem:testdb
driver-class-name: org.h2.Driver
username: sa
password: ""
initial-size: 5
max-total: 5
max-idle: 5
min-idle: 5
between-eviction-millis: 300000
min-evictable-idle-millis: 600000
num-tests-per-eviction-run: 3
server:
port: 10396
shutdown: graceful
eureka:
client:
enabled: false
- 유레카에 등록이 되어야하나?
- 우리는 사실 필요없긴한데 그래도 등록하는게 좋을것같긴하다 여러 의미로
- 유레카 대시보드로 확인할 수도 있고
- 지금은 따로 요청이나 이런건 없지만 요청을 주고받을수도 있을테니까
- rest api 로 상태를 체크할수도 있을테니까
DBCP2 설정 추가
@Getter @Setter
@Configuration
@ConfigurationProperties(prefix = "dbcp2.datasource")
public class DataSourceConfig {
private String driverClassName;
private String url;
private String username;
private String password;
private Integer maxIdle;
private Integer maxTotal;
private Integer initialSize;
private Integer minIdle;
private Long betweenEvictionMillis;
private Long minEvictableIdleMillis;
private Integer numTestsPerEvictionRun;
@Bean
public DataSource dataSource() {
BasicDataSource basicDataSource = new BasicDataSource();
basicDataSource.setDriverClassName(driverClassName);
basicDataSource.setUrl(url);
basicDataSource.setUsername(username);
basicDataSource.setPassword(password);
basicDataSource.setMaxIdle(maxIdle);
basicDataSource.setMaxTotal(maxTotal);
basicDataSource.setInitialSize(initialSize);
basicDataSource.setMinIdle(minIdle);
basicDataSource.setValidationQuery("SELECT 1");
basicDataSource.setTestOnReturn(true);
basicDataSource.setTestOnBorrow(true);
basicDataSource.setTestWhileIdle(true);
basicDataSource.setDurationBetweenEvictionRuns(Duration.ofMinutes(betweenEvictionMillis));
basicDataSource.setMinEvictableIdle(Duration.ofMinutes(minEvictableIdleMillis));
basicDataSource.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
return basicDataSource;
}
}
기본으로 설정된 Job이 없는에러
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jobLauncherApplicationRunner' defined in class path resource [org/springframework/boot/autoconfigure/batch/BatchAutoConfiguration.class]: Job name must be specified in case of multiple jobs
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1806)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:600)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:522)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:337)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:335)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:975)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:971)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:625)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:755)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:456)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:335)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1364)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1353)
at shop.wannab.batchserver.BatchserverApplication.main(BatchserverApplication.java:10)
Caused by: java.lang.IllegalArgumentException: Job name must be specified in case of multiple jobs
at org.springframework.util.Assert.isTrue(Assert.java:111)
at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.afterPropertiesSet(JobLauncherApplicationRunner.java:115)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1853)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1802)
... 16 common frames omitted
코드 보니 스케쥴러로 실행하는거같은데
@Component
@RequiredArgsConstructor
@EnableScheduling
public class BatchScheduler {
private final JobLauncher jobLauncher;
private final Job updateUserGradeJob;
private final Job updateUserStateJob;
// TODO : 변경 필요
@Scheduled(cron = "0 */2 * * * ?")
public void runUpdateUserGradeJob() throws Exception {
JobParameters params = new JobParametersBuilder()
.addLong("time", System.currentTimeMillis())
.toJobParameters();
jobLauncher.run(updateUserGradeJob, params);
}
// TODO : 변경 필요
@Scheduled(cron = "0 1/2 * * * ?")
public void runUpdateUserStateJob() throws Exception {
JobParameters params = new JobParametersBuilder()
.addLong("time", System.currentTimeMillis())
.toJobParameters();
jobLauncher.run(updateUserStateJob, params);
}
}
yml에 추가
batch:
job:
enabled: false
Batch schedule yml로 빼기
batch:
schedule:
update-user-grade: "0 0 0 1 * ?"
update-user-state: "0 0 1 1 * ?"
@Getter @Setter
@Component
@ConfigurationProperties(prefix = "batch.schedule")
public class BatchScheduleProperties {
private String updateUserGrade;
private String updateUserState;
}
- yml 값을 configuration properties로 주입받고
@Slf4j
@Component
@RequiredArgsConstructor
@EnableScheduling
public class BatchScheduler implements SchedulingConfigurer {
private final JobLauncher jobLauncher;
private final Job updateUserGradeJob;
private final Job updateUserStateJob;
private final BatchScheduleProperties scheduleProperties;
public void runUpdateUserGradeJob() {
JobParameters params = new JobParametersBuilder()
.addLong("time", System.currentTimeMillis())
.toJobParameters();
try {
jobLauncher.run(updateUserGradeJob, params);
} catch (Exception e) {
log.error("runUpdateUserGradeJob Error : {}", e.getMessage());
}
}
public void runUpdateUserStateJob() {
JobParameters params = new JobParametersBuilder()
.addLong("time", System.currentTimeMillis())
.toJobParameters();
try{
jobLauncher.run(updateUserStateJob, params);
} catch (Exception e){
log.error("runUpdateUserStateJob Error : {}", e.getMessage());
}
}
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.addCronTask(this::runUpdateUserGradeJob, scheduleProperties.getUpdateUserGrade());
taskRegistrar.addCronTask(this::runUpdateUserStateJob, scheduleProperties.getUpdateUserState());
}
}
- 여기에서 의존성 주입받고 configureTask를 통해서 값을 설정해줌
- 원래 IOException을 명시적으로 던져야하는데 SneakyThrows로 일단 통과시킴