Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,62 @@

import com.linkedin.openhouse.optimizer.model.OperationTypeDto;
import java.util.Map;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.ExitCodeGenerator;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.Bean;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

/** Entry point for the Optimizer Scheduler application. */
/**
* Entry point for the Optimizer Scheduler application.
*
* <p>Spring Batch–style: implements {@link CommandLineRunner} so the work runs after context
* startup, and {@link ExitCodeGenerator} so the JVM exit code reflects batch outcome. {@code
* SpringApplication.exit(...)} closes the context (triggers {@code @PreDestroy} hooks, drains the
* JPA pool, etc.) so the k8s CronJob pod terminates cleanly with a status reflecting reality.
*/
@Slf4j
@SpringBootApplication
@EntityScan(basePackages = "com.linkedin.openhouse.optimizer.db")
@EnableJpaRepositories(basePackages = "com.linkedin.openhouse.optimizer.repository")
public class SchedulerApplication {
public class SchedulerApplication implements CommandLineRunner, ExitCodeGenerator {

private final SchedulerRunner runner;
private final Map<OperationTypeDto, BinPacker> binPackers;
private int exitCode = 0;

@Autowired
public SchedulerApplication(SchedulerRunner runner, Map<OperationTypeDto, BinPacker> binPackers) {
this.runner = runner;
this.binPackers = binPackers;
}

public static void main(String[] args) {
SpringApplication.run(SchedulerApplication.class, args);
System.exit(SpringApplication.exit(SpringApplication.run(SchedulerApplication.class, args)));
}

/**
* Runs the scheduler once per registered {@link BinPacker} per process invocation. Each call is
* scoped to one operation type.
* scoped to one operation type. Any thrown exception is logged and surfaces as a non-zero exit
* code via {@link #getExitCode()} after the context is shut down cleanly.
*/
@Bean
public CommandLineRunner run(
SchedulerRunner runner, Map<OperationTypeDto, BinPacker> binPackers) {
return args -> binPackers.keySet().forEach(runner::schedule);
@Override
public void run(String... args) {
try {
log.info("Scheduler starting; operation types: {}", binPackers.keySet());
binPackers.keySet().forEach(runner::schedule);
log.info("Scheduler completed successfully");
} catch (Exception e) {
log.error("Scheduler failed", e);
exitCode = 1;
}
}

@Override
public int getExitCode() {
return exitCode;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
spring.application.name=openhouse-optimizer-scheduler
spring.main.web-application-type=none
spring.main.banner-mode=off
spring.datasource.url=${OPTIMIZER_DB_URL:jdbc:h2:mem:schedulerdb;DB_CLOSE_DELAY=-1;MODE=MySQL}
spring.datasource.username=${OPTIMIZER_DB_USER:sa}
spring.datasource.password=${OPTIMIZER_DB_PASSWORD:}
Expand Down