Loading src/main/java/org/etsi/osl/metrico/MetricoController.java +28 −3 Changes for src/main/java/org/etsi/osl/metrico/MetricoController.java: 28 added lines, 3 removed lines. Original line number Diff line number Diff line package org.etsi.osl.metrico; import org.etsi.osl.metrico.model.Job; import org.etsi.osl.metrico.model.StartPeriodicQueryRequest; import org.etsi.osl.metrico.prometheus.PrometheusQueries; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.*; import java.util.Arrays; Loading Loading @@ -39,6 +40,30 @@ public class MetricoController { return new ResponseEntity<>(Arrays.toString(prometheusData), HttpStatus.OK); } @PostMapping("/startPeriodicQuery") public ResponseEntity<String> startPeriodicQuery(@RequestBody StartPeriodicQueryRequest request) { logger.atDebug().setMessage("/startPeriodicQuery endpoint called with request body: " + request).log(); logger.atInfo().setMessage("/startPeriodicQuery endpoint called with query: " + request.getQuery()).log(); if (request.getProm_ip() == null) { logger.atInfo().setMessage("/startPeriodicQuery endpoint called without a prometheus_ip: " + request).log(); HttpHeaders responseHeaders = new HttpHeaders(); responseHeaders.set("Error", "prom_ip parameter is missing"); return new ResponseEntity<>("prom_ip parameter is missing", responseHeaders, HttpStatus.BAD_REQUEST); } if (request.getQuery() == null) { logger.atInfo().setMessage("/startPeriodicQuery endpoint called without a query: " + request).log(); HttpHeaders responseHeaders = new HttpHeaders(); responseHeaders.set("Error", "query parameter is missing"); return new ResponseEntity<>("query parameter is missing", responseHeaders, HttpStatus.BAD_REQUEST); } if (request.getEndDateTime() == null){ logger.atDebug().setMessage("/startPeriodicQuery endpoint called without a stopAfterSeconds. Job will not stop by itself.").log(); } String prom_url = request.getProtocol() + "://" + request.getProm_ip() + ":" + request.getProm_port(); Job newPeriodicQuery = PrometheusQueries.startPeriodicQuery(prom_url, request.getQuery(), request.getStartDateTime(), request.getEndDateTime(), request.getExecutionInterval() ); return new ResponseEntity<>("Periodic query started, with ID: " + newPeriodicQuery.getUuid(), HttpStatus.OK); } } src/main/java/org/etsi/osl/metrico/MetricoSpringBoot.java +2 −1 Changes for src/main/java/org/etsi/osl/metrico/MetricoSpringBoot.java: 2 added lines, 1 removed line. Original line number Diff line number Diff line Loading @@ -7,10 +7,11 @@ import org.springframework.boot.ExitCodeGenerator; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.ApplicationContext; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; @SpringBootApplication @EnableJpaRepositories public class MetricoSpringBoot implements CommandLineRunner { private static final Logger logger = Loading src/main/java/org/etsi/osl/metrico/model/Job.java +54 −15 Changes for src/main/java/org/etsi/osl/metrico/model/Job.java: 54 added lines, 15 removed lines. Original line number Diff line number Diff line Loading @@ -4,11 +4,16 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import jakarta.persistence.*; import lombok.Getter; import lombok.Setter; import org.etsi.osl.metrico.repo.JobRepository; import org.etsi.osl.metrico.reposervices.JobRepoService; import org.etsi.osl.tmf.pm628.model.ExecutionStateType; import org.hibernate.annotations.GenericGenerator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.format.annotation.DateTimeFormat; import java.time.Duration; import java.time.OffsetDateTime; import java.util.Map; import java.util.UUID; import java.util.concurrent.*; Loading @@ -26,6 +31,14 @@ public class Job{ private ExecutionStateType state; @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) private OffsetDateTime startDateTime; @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) private OffsetDateTime endDateTime; private Integer executionInterval; @JsonIgnore private boolean deleted = false; Loading @@ -43,41 +56,67 @@ public class Job{ public Job() { this.state = ExecutionStateType.PENDING; this.executionInterval = 10; this.startDateTime = OffsetDateTime.now(); } public Job(OffsetDateTime stopDateTime){ this(); this.endDateTime = stopDateTime; } public Job(OffsetDateTime startDateTime, OffsetDateTime endDateTime){ this(endDateTime); this.startDateTime = startDateTime; } public Job(OffsetDateTime startDateTime, OffsetDateTime endDateTime, Integer executionInterval){ this(startDateTime, endDateTime); this.executionInterval = executionInterval; } private static final Logger logger = LoggerFactory.getLogger(Job.class); @Getter private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); private static final Map<UUID, Job> jobs = new ConcurrentHashMap<>(); private static JobRepoService jobRepoService; /** * Schedules a new job to be executed periodically. * Schedules a new job to be executed periodically based on the provided parameters. * <p> * This method creates a new job with a unique identifier, schedules it to run at a fixed rate * with the specified initial delay and periodic delay. The job's execution state is initially set * to {@link ExecutionStateType#PENDING}. If the job is successfully scheduled, its state changes to * {@link ExecutionStateType#INPROGRESS}. If the job cannot be scheduled due to a * {@link RejectedExecutionException}, its state is set to {@link ExecutionStateType#FAILED}. * This method initializes a new {@link Job} instance with the specified start and end date times, and execution interval. * It calculates the initial delay as the difference in seconds between the current time and the start date time. * The job is initially set to a PENDING state. It then attempts to schedule the job to run at a fixed rate, * starting after the initial delay and subsequently with the specified execution interval. * If the job is successfully scheduled, its state is updated to INPROGRESS, and it is logged. * In case of a scheduling failure due to a {@link RejectedExecutionException}, the job's state is set to FAILED, * and the error is logged. * </p> * * @param task the task to be executed by the job * @param initialDelay the time to delay first execution, in seconds * @param periodicDelay the period between successive executions, in seconds * @return the scheduled job with its unique identifier and state * @param task the {@link Runnable} task that the job will execute * @param startDateTime the {@link OffsetDateTime} specifying when the job should start * @param endDateTime the {@link OffsetDateTime} specifying when the job should end * @param executionInterval the interval, in seconds, between successive executions of the job * @return the newly created and scheduled {@link Job} instance * @throws RejectedExecutionException if the task cannot be scheduled for execution */ public Job startJob(Runnable task, long initialDelay, long periodicDelay) { Job job = new Job(); public static Job startJob(Runnable task, OffsetDateTime startDateTime, OffsetDateTime endDateTime, Integer executionInterval) { Job job = new Job(startDateTime, endDateTime, executionInterval); long initialDelay = Duration.between(OffsetDateTime.now(), startDateTime).getSeconds(); job.setState(ExecutionStateType.PENDING); jobRepoService.createAndSaveJob(); UUID jobId = job.getUuid(); try { ScheduledFuture<?> future = scheduler.scheduleAtFixedRate(task, initialDelay, periodicDelay, TimeUnit.SECONDS); ScheduledFuture<?> future = scheduler.scheduleAtFixedRate(task, initialDelay, executionInterval, TimeUnit.SECONDS); job.setFuture(future); jobs.put(jobId, job); job.setState(ExecutionStateType.INPROGRESS); logger.info("Job with ID {} started successfully.", jobId); jobRepoService.updateJob(jobId, job.getState()); } catch (RejectedExecutionException e) { job.setState(ExecutionStateType.FAILED); logger.error("Job with ID {} could not be scheduled.", jobId, e); Loading @@ -99,7 +138,7 @@ public class Job{ * * @param jobId the UUID of the job to stop */ public void stopJob(UUID jobId) { public static void stopJob(UUID jobId) { Job job = jobs.get(jobId); if (job != null) { if (job.getState() == ExecutionStateType.CANCELLED ) { Loading src/main/java/org/etsi/osl/metrico/model/MonitoringJob.javadeleted 100644 → 0 +0 −34 Changes for src/main/java/org/etsi/osl/metrico/model/MonitoringJob.java: 0 added lines, 34 removed lines. Original line number Diff line number Diff line package org.etsi.osl.metrico.model; import jakarta.persistence.Entity; import lombok.Getter; import lombok.Setter; import org.springframework.format.annotation.DateTimeFormat; import java.time.OffsetDateTime; @Setter @Getter @Entity public class MonitoringJob extends Job{ @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) private OffsetDateTime startDateTime; @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) private OffsetDateTime endDateTime; private Integer executionInterval; public MonitoringJob(){ executionInterval = 10; } public MonitoringJob(OffsetDateTime startDateTime, OffsetDateTime endDateTime){ this.startDateTime = startDateTime; this.endDateTime = endDateTime; this.executionInterval = 10; } } src/main/java/org/etsi/osl/metrico/model/StartPeriodicQueryRequest.java +6 −4 Changes for src/main/java/org/etsi/osl/metrico/model/StartPeriodicQueryRequest.java: 6 added lines, 4 removed lines. Original line number Diff line number Diff line Loading @@ -2,6 +2,9 @@ package org.etsi.osl.metrico.model; import lombok.Getter; import lombok.Setter; import org.springframework.format.annotation.DateTimeFormat; import java.time.OffsetDateTime; @Setter @Getter Loading @@ -10,8 +13,7 @@ public class StartPeriodicQueryRequest { private String prom_ip; private String prom_port = "9090"; private String query; private int initialDelay = 0; private int periodicDelay = 300; private int stopAfterSeconds = 0; private OffsetDateTime startDateTime; private OffsetDateTime endDateTime; private int executionInterval = 300; } Loading
src/main/java/org/etsi/osl/metrico/MetricoController.java +28 −3 Changes for src/main/java/org/etsi/osl/metrico/MetricoController.java: 28 added lines, 3 removed lines. Original line number Diff line number Diff line package org.etsi.osl.metrico; import org.etsi.osl.metrico.model.Job; import org.etsi.osl.metrico.model.StartPeriodicQueryRequest; import org.etsi.osl.metrico.prometheus.PrometheusQueries; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.*; import java.util.Arrays; Loading Loading @@ -39,6 +40,30 @@ public class MetricoController { return new ResponseEntity<>(Arrays.toString(prometheusData), HttpStatus.OK); } @PostMapping("/startPeriodicQuery") public ResponseEntity<String> startPeriodicQuery(@RequestBody StartPeriodicQueryRequest request) { logger.atDebug().setMessage("/startPeriodicQuery endpoint called with request body: " + request).log(); logger.atInfo().setMessage("/startPeriodicQuery endpoint called with query: " + request.getQuery()).log(); if (request.getProm_ip() == null) { logger.atInfo().setMessage("/startPeriodicQuery endpoint called without a prometheus_ip: " + request).log(); HttpHeaders responseHeaders = new HttpHeaders(); responseHeaders.set("Error", "prom_ip parameter is missing"); return new ResponseEntity<>("prom_ip parameter is missing", responseHeaders, HttpStatus.BAD_REQUEST); } if (request.getQuery() == null) { logger.atInfo().setMessage("/startPeriodicQuery endpoint called without a query: " + request).log(); HttpHeaders responseHeaders = new HttpHeaders(); responseHeaders.set("Error", "query parameter is missing"); return new ResponseEntity<>("query parameter is missing", responseHeaders, HttpStatus.BAD_REQUEST); } if (request.getEndDateTime() == null){ logger.atDebug().setMessage("/startPeriodicQuery endpoint called without a stopAfterSeconds. Job will not stop by itself.").log(); } String prom_url = request.getProtocol() + "://" + request.getProm_ip() + ":" + request.getProm_port(); Job newPeriodicQuery = PrometheusQueries.startPeriodicQuery(prom_url, request.getQuery(), request.getStartDateTime(), request.getEndDateTime(), request.getExecutionInterval() ); return new ResponseEntity<>("Periodic query started, with ID: " + newPeriodicQuery.getUuid(), HttpStatus.OK); } }
src/main/java/org/etsi/osl/metrico/MetricoSpringBoot.java +2 −1 Changes for src/main/java/org/etsi/osl/metrico/MetricoSpringBoot.java: 2 added lines, 1 removed line. Original line number Diff line number Diff line Loading @@ -7,10 +7,11 @@ import org.springframework.boot.ExitCodeGenerator; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.ApplicationContext; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; @SpringBootApplication @EnableJpaRepositories public class MetricoSpringBoot implements CommandLineRunner { private static final Logger logger = Loading
src/main/java/org/etsi/osl/metrico/model/Job.java +54 −15 Changes for src/main/java/org/etsi/osl/metrico/model/Job.java: 54 added lines, 15 removed lines. Original line number Diff line number Diff line Loading @@ -4,11 +4,16 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import jakarta.persistence.*; import lombok.Getter; import lombok.Setter; import org.etsi.osl.metrico.repo.JobRepository; import org.etsi.osl.metrico.reposervices.JobRepoService; import org.etsi.osl.tmf.pm628.model.ExecutionStateType; import org.hibernate.annotations.GenericGenerator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.format.annotation.DateTimeFormat; import java.time.Duration; import java.time.OffsetDateTime; import java.util.Map; import java.util.UUID; import java.util.concurrent.*; Loading @@ -26,6 +31,14 @@ public class Job{ private ExecutionStateType state; @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) private OffsetDateTime startDateTime; @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) private OffsetDateTime endDateTime; private Integer executionInterval; @JsonIgnore private boolean deleted = false; Loading @@ -43,41 +56,67 @@ public class Job{ public Job() { this.state = ExecutionStateType.PENDING; this.executionInterval = 10; this.startDateTime = OffsetDateTime.now(); } public Job(OffsetDateTime stopDateTime){ this(); this.endDateTime = stopDateTime; } public Job(OffsetDateTime startDateTime, OffsetDateTime endDateTime){ this(endDateTime); this.startDateTime = startDateTime; } public Job(OffsetDateTime startDateTime, OffsetDateTime endDateTime, Integer executionInterval){ this(startDateTime, endDateTime); this.executionInterval = executionInterval; } private static final Logger logger = LoggerFactory.getLogger(Job.class); @Getter private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); private static final Map<UUID, Job> jobs = new ConcurrentHashMap<>(); private static JobRepoService jobRepoService; /** * Schedules a new job to be executed periodically. * Schedules a new job to be executed periodically based on the provided parameters. * <p> * This method creates a new job with a unique identifier, schedules it to run at a fixed rate * with the specified initial delay and periodic delay. The job's execution state is initially set * to {@link ExecutionStateType#PENDING}. If the job is successfully scheduled, its state changes to * {@link ExecutionStateType#INPROGRESS}. If the job cannot be scheduled due to a * {@link RejectedExecutionException}, its state is set to {@link ExecutionStateType#FAILED}. * This method initializes a new {@link Job} instance with the specified start and end date times, and execution interval. * It calculates the initial delay as the difference in seconds between the current time and the start date time. * The job is initially set to a PENDING state. It then attempts to schedule the job to run at a fixed rate, * starting after the initial delay and subsequently with the specified execution interval. * If the job is successfully scheduled, its state is updated to INPROGRESS, and it is logged. * In case of a scheduling failure due to a {@link RejectedExecutionException}, the job's state is set to FAILED, * and the error is logged. * </p> * * @param task the task to be executed by the job * @param initialDelay the time to delay first execution, in seconds * @param periodicDelay the period between successive executions, in seconds * @return the scheduled job with its unique identifier and state * @param task the {@link Runnable} task that the job will execute * @param startDateTime the {@link OffsetDateTime} specifying when the job should start * @param endDateTime the {@link OffsetDateTime} specifying when the job should end * @param executionInterval the interval, in seconds, between successive executions of the job * @return the newly created and scheduled {@link Job} instance * @throws RejectedExecutionException if the task cannot be scheduled for execution */ public Job startJob(Runnable task, long initialDelay, long periodicDelay) { Job job = new Job(); public static Job startJob(Runnable task, OffsetDateTime startDateTime, OffsetDateTime endDateTime, Integer executionInterval) { Job job = new Job(startDateTime, endDateTime, executionInterval); long initialDelay = Duration.between(OffsetDateTime.now(), startDateTime).getSeconds(); job.setState(ExecutionStateType.PENDING); jobRepoService.createAndSaveJob(); UUID jobId = job.getUuid(); try { ScheduledFuture<?> future = scheduler.scheduleAtFixedRate(task, initialDelay, periodicDelay, TimeUnit.SECONDS); ScheduledFuture<?> future = scheduler.scheduleAtFixedRate(task, initialDelay, executionInterval, TimeUnit.SECONDS); job.setFuture(future); jobs.put(jobId, job); job.setState(ExecutionStateType.INPROGRESS); logger.info("Job with ID {} started successfully.", jobId); jobRepoService.updateJob(jobId, job.getState()); } catch (RejectedExecutionException e) { job.setState(ExecutionStateType.FAILED); logger.error("Job with ID {} could not be scheduled.", jobId, e); Loading @@ -99,7 +138,7 @@ public class Job{ * * @param jobId the UUID of the job to stop */ public void stopJob(UUID jobId) { public static void stopJob(UUID jobId) { Job job = jobs.get(jobId); if (job != null) { if (job.getState() == ExecutionStateType.CANCELLED ) { Loading
src/main/java/org/etsi/osl/metrico/model/MonitoringJob.javadeleted 100644 → 0 +0 −34 Changes for src/main/java/org/etsi/osl/metrico/model/MonitoringJob.java: 0 added lines, 34 removed lines. Original line number Diff line number Diff line package org.etsi.osl.metrico.model; import jakarta.persistence.Entity; import lombok.Getter; import lombok.Setter; import org.springframework.format.annotation.DateTimeFormat; import java.time.OffsetDateTime; @Setter @Getter @Entity public class MonitoringJob extends Job{ @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) private OffsetDateTime startDateTime; @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) private OffsetDateTime endDateTime; private Integer executionInterval; public MonitoringJob(){ executionInterval = 10; } public MonitoringJob(OffsetDateTime startDateTime, OffsetDateTime endDateTime){ this.startDateTime = startDateTime; this.endDateTime = endDateTime; this.executionInterval = 10; } }
src/main/java/org/etsi/osl/metrico/model/StartPeriodicQueryRequest.java +6 −4 Changes for src/main/java/org/etsi/osl/metrico/model/StartPeriodicQueryRequest.java: 6 added lines, 4 removed lines. Original line number Diff line number Diff line Loading @@ -2,6 +2,9 @@ package org.etsi.osl.metrico.model; import lombok.Getter; import lombok.Setter; import org.springframework.format.annotation.DateTimeFormat; import java.time.OffsetDateTime; @Setter @Getter Loading @@ -10,8 +13,7 @@ public class StartPeriodicQueryRequest { private String prom_ip; private String prom_port = "9090"; private String query; private int initialDelay = 0; private int periodicDelay = 300; private int stopAfterSeconds = 0; private OffsetDateTime startDateTime; private OffsetDateTime endDateTime; private int executionInterval = 300; }