parent
0beef25bd5
commit
41598ca440
@ -0,0 +1,28 @@
|
|||||||
|
package kr.re.etri.autoflow.batch;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.batch.core.Job;
|
||||||
|
import org.springframework.batch.core.JobParameters;
|
||||||
|
import org.springframework.batch.core.JobParametersBuilder;
|
||||||
|
import org.springframework.batch.core.launch.JobLauncher;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableScheduling
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class BatchScheduler {
|
||||||
|
|
||||||
|
private final JobLauncher jobLauncher;
|
||||||
|
private final Job runSyncJob; // ✅ Spring Batch의 Job 타입
|
||||||
|
|
||||||
|
@Scheduled(fixedRate = 60000) // 1분마다 실행
|
||||||
|
public void runJob() throws Exception {
|
||||||
|
JobParameters params = new JobParametersBuilder()
|
||||||
|
.addLong("timestamp", System.currentTimeMillis()) // 중복 실행 방지
|
||||||
|
.toJobParameters();
|
||||||
|
|
||||||
|
jobLauncher.run(runSyncJob, params);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,126 @@
|
|||||||
|
package kr.re.etri.autoflow.batch;
|
||||||
|
|
||||||
|
import kr.re.etri.autoflow.entity.KubeflowRunEntity;
|
||||||
|
import kr.re.etri.autoflow.payload.request.KubeflowRunRequest;
|
||||||
|
import kr.re.etri.autoflow.payload.response.KubeflowRunResponse;
|
||||||
|
import kr.re.etri.autoflow.repository.KubeflowRunRepository;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.batch.core.Job;
|
||||||
|
import org.springframework.batch.core.Step;
|
||||||
|
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
|
||||||
|
import org.springframework.batch.core.job.builder.JobBuilder;
|
||||||
|
import org.springframework.batch.core.repository.JobRepository;
|
||||||
|
import org.springframework.batch.core.step.builder.StepBuilder;
|
||||||
|
import org.springframework.batch.item.ItemProcessor;
|
||||||
|
import org.springframework.batch.item.ItemReader;
|
||||||
|
import org.springframework.batch.item.ItemWriter;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.transaction.PlatformTransactionManager;
|
||||||
|
import org.springframework.web.reactive.function.client.ExchangeStrategies;
|
||||||
|
import org.springframework.web.reactive.function.client.WebClient;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableBatchProcessing
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class KubeflowRunBatchConfig {
|
||||||
|
|
||||||
|
private final JobRepository jobRepository;
|
||||||
|
private final PlatformTransactionManager transactionManager;
|
||||||
|
private final KubeflowRunRepository kubeflowRunRepository;
|
||||||
|
|
||||||
|
// 최신 데이터 몇 개만 가져올지
|
||||||
|
private static final int PAGE_SIZE = 50;
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public WebClient.Builder webClientBuilder() {
|
||||||
|
return WebClient.builder()
|
||||||
|
.baseUrl("http://192.168.10.135:32473")
|
||||||
|
.exchangeStrategies(ExchangeStrategies.builder()
|
||||||
|
.codecs(configurer -> configurer.defaultCodecs()
|
||||||
|
.maxInMemorySize(16 * 1024 * 1024)) // 16MB 버퍼
|
||||||
|
.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public Job runSyncJob() {
|
||||||
|
return new JobBuilder("runSyncJob", jobRepository)
|
||||||
|
.start(runStep())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public Step runStep() {
|
||||||
|
return new StepBuilder("runStep", jobRepository)
|
||||||
|
.<KubeflowRunRequest, KubeflowRunEntity>chunk(10, transactionManager)
|
||||||
|
.reader(runReader())
|
||||||
|
.processor(runProcessor())
|
||||||
|
.writer(runWriter())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ItemReader<KubeflowRunRequest> runReader() {
|
||||||
|
return new ItemReader<>() {
|
||||||
|
private boolean read = false;
|
||||||
|
private List<KubeflowRunRequest> runs;
|
||||||
|
private int index = 0;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KubeflowRunRequest read() {
|
||||||
|
if (!read) {
|
||||||
|
WebClient client = webClientBuilder().build();
|
||||||
|
KubeflowRunResponse response = client.get()
|
||||||
|
.uri(uriBuilder -> uriBuilder
|
||||||
|
.path("/apis/v2beta1/runs")
|
||||||
|
.queryParam("page_size", PAGE_SIZE)
|
||||||
|
.build())
|
||||||
|
.retrieve()
|
||||||
|
.bodyToMono(KubeflowRunResponse.class)
|
||||||
|
.block();
|
||||||
|
|
||||||
|
runs = response != null ? response.getRuns() : List.of();
|
||||||
|
read = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (runs != null && index < runs.size()) {
|
||||||
|
return runs.get(index++);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ItemProcessor<KubeflowRunRequest, KubeflowRunEntity> runProcessor() {
|
||||||
|
return dto -> {
|
||||||
|
// DB에서 이미 존재하는 runId 체크
|
||||||
|
if (kubeflowRunRepository.existsById(dto.getRun_id())) {
|
||||||
|
return null; // 중복이면 skip
|
||||||
|
}
|
||||||
|
|
||||||
|
KubeflowRunEntity entity = new KubeflowRunEntity();
|
||||||
|
entity.setRunId(dto.getRun_id());
|
||||||
|
entity.setExperimentId(dto.getExperiment_id());
|
||||||
|
entity.setDisplayName(dto.getDisplay_name());
|
||||||
|
entity.setStorageState(dto.getStorage_state());
|
||||||
|
entity.setDescription(dto.getDescription());
|
||||||
|
entity.setPipelineId(dto.getPipeline_version_reference().getPipeline_id());
|
||||||
|
entity.setPipelineVersionId(dto.getPipeline_version_reference().getPipeline_version_id());
|
||||||
|
entity.setServiceAccount(dto.getService_account());
|
||||||
|
entity.setCreatedAt(Instant.parse(dto.getCreated_at()));
|
||||||
|
entity.setScheduledAt(Instant.parse(dto.getScheduled_at()));
|
||||||
|
entity.setFinishedAt(Instant.parse(dto.getFinished_at()));
|
||||||
|
entity.setState(dto.getState());
|
||||||
|
return entity;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ItemWriter<KubeflowRunEntity> runWriter() {
|
||||||
|
return items -> kubeflowRunRepository.saveAll(items);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
package kr.re.etri.autoflow.entity;
|
||||||
|
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
|
||||||
|
// Entity (DB 저장용)
|
||||||
|
@Entity
|
||||||
|
@Table(name = "tb_runs")
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class KubeflowRunEntity {
|
||||||
|
@Id
|
||||||
|
private String runId;
|
||||||
|
|
||||||
|
private String experimentId;
|
||||||
|
private String displayName;
|
||||||
|
private String storageState;
|
||||||
|
private String description;
|
||||||
|
private String pipelineId;
|
||||||
|
private String pipelineVersionId;
|
||||||
|
private String serviceAccount;
|
||||||
|
|
||||||
|
private Instant createdAt;
|
||||||
|
private Instant scheduledAt;
|
||||||
|
private Instant finishedAt;
|
||||||
|
private String state;
|
||||||
|
}
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
package kr.re.etri.autoflow.payload.request;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class KubeflowRunRequest {
|
||||||
|
private String run_id;
|
||||||
|
private String experiment_id;
|
||||||
|
private String display_name;
|
||||||
|
private String storage_state;
|
||||||
|
private String description;
|
||||||
|
private PipelineVersionRef pipeline_version_reference;
|
||||||
|
private String service_account;
|
||||||
|
private String created_at;
|
||||||
|
private String scheduled_at;
|
||||||
|
private String finished_at;
|
||||||
|
private String state;
|
||||||
|
}
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
package kr.re.etri.autoflow.payload.request;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class PipelineVersionRef {
|
||||||
|
private String pipeline_id;
|
||||||
|
private String pipeline_version_id;
|
||||||
|
}
|
||||||
@ -0,0 +1,13 @@
|
|||||||
|
package kr.re.etri.autoflow.payload.response;
|
||||||
|
|
||||||
|
import kr.re.etri.autoflow.payload.request.KubeflowRunRequest;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class KubeflowRunResponse {
|
||||||
|
private List<KubeflowRunRequest> runs;
|
||||||
|
private int total_size;
|
||||||
|
private String next_page_token;
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
package kr.re.etri.autoflow.repository;
|
||||||
|
|
||||||
|
import kr.re.etri.autoflow.entity.KubeflowRunEntity;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
|
||||||
|
public interface KubeflowRunRepository extends JpaRepository<KubeflowRunEntity, String> {
|
||||||
|
}
|
||||||
Loading…
Reference in new issue