Skip to content
Open
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
36 changes: 29 additions & 7 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,8 @@

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<gasw-version>4.3</gasw-version>
<maven.compiler.release>21</maven.compiler.release>
<gasw-version>4.6-SNAPSHOT</gasw-version>
</properties>

<licenses>
Expand All @@ -32,6 +31,21 @@

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
<configuration>
<release>${maven.compiler.release}</release>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.38</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
Expand Down Expand Up @@ -63,6 +77,13 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.5.2</version>
<configuration>
<argLine>
-Dnet.bytebuddy.experimental=true
-javaagent:"${settings.localRepository}/org/mockito/mockito-core/5.14.2/mockito-core-5.14.2.jar"
--add-opens java.base/java.lang=ALL-UNNAMED
</argLine>
</configuration>
</plugin>
</plugins>
</build>
Expand All @@ -73,7 +94,7 @@
<artifactId>joda-time</artifactId>
<version>2.13.0</version>
</dependency>
<dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.17.2</version>
Expand All @@ -98,7 +119,8 @@
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.34</version>
<version>1.18.38</version> <!-- Alignée sur le compilateur -->
<scope>provided</scope>
</dependency>
<dependency>
<groupId>net.i2p.crypto</groupId>
Expand All @@ -108,7 +130,7 @@
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>5.13.0</version>
<version>5.14.2</version>
<scope>test</scope>
</dependency>
</dependencies>
Expand All @@ -134,4 +156,4 @@
<url>https://vip.creatis.insa-lyon.fr:9007/nexus/repository/snapshots</url>
</snapshotRepository>
</distributionManagement>
</project>
</project>
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package fr.insalyon.creatis.gasw.executor.batch;

import java.util.Date;

import java.util.Map;
import fr.insalyon.creatis.gasw.bean.JobMetric;
import fr.insalyon.creatis.gasw.GaswConfiguration;
import fr.insalyon.creatis.gasw.GaswException;
import fr.insalyon.creatis.gasw.bean.Job;
Expand All @@ -17,7 +18,7 @@
import lombok.extern.slf4j.Slf4j;

@Slf4j
final public class BatchMonitor extends GaswMonitor {

Check warning on line 21 in src/main/java/fr/insalyon/creatis/gasw/executor/batch/BatchMonitor.java

View workflow job for this annotation

GitHub Actions / all

This class has too many methods, consider refactoring it.

A class with too many methods is probably a good suspect for refactoring, in order to reduce its complexity and find a way to have more fine grained objects. TooManyMethods (Priority: 3, Ruleset: Design) https://docs.pmd-code.org/snapshot/pmd_rules_java_design.html#toomanymethods

@Getter
@Setter
Expand All @@ -29,7 +30,7 @@
super();
}

private boolean notRunningJob(GaswStatus s) {

Check warning on line 33 in src/main/java/fr/insalyon/creatis/gasw/executor/batch/BatchMonitor.java

View workflow job for this annotation

GitHub Actions / all

Parameter 's' is not assigned and could be declared final

Reports method and constructor parameters that can be made final because they are never reassigned within the body of the method. This rule ignores unused parameters so as not to overlap with the rule {% rule java/bestpractices/UnusedFormalParameter %}. It will also ignore the parameters of abstract methods. MethodArgumentCouldBeFinal (Priority: 3, Ruleset: Code Style) https://docs.pmd-code.org/snapshot/pmd_rules_java_codestyle.html#methodargumentcouldbefinal
return s != GaswStatus.RUNNING
&& s != GaswStatus.QUEUED
&& s != GaswStatus.UNDEFINED
Expand All @@ -37,7 +38,7 @@
}

@Override
public void run() {

Check warning on line 41 in src/main/java/fr/insalyon/creatis/gasw/executor/batch/BatchMonitor.java

View workflow job for this annotation

GitHub Actions / all

The method 'run()' has a cyclomatic complexity of 11.

The complexity of methods directly affects maintenance costs and readability. Concentrating too much decisional logic in a single method makes its behaviour hard to read and change. Cyclomatic complexity assesses the complexity of a method by counting the number of decision points in a method, plus one for the method entry. Decision points are places where the control flow jumps to another place in the program. As such, they include all control flow statements, such as `if`, `while`, `for`, and `case`. For more details on the calculation, see the documentation {% jdoc java::lang.java.metrics.JavaMetrics#CYCLO %}. Generally, numbers ranging from 1-4 denote low complexity, 5-7 denote moderate complexity, 8-10 denote high complexity, and 11+ is very high complexity. By default, this rule reports methods with a complexity >= 10. Additionally, classes with many methods of moderate complexity get reported as well once the total of their methods' complexities reaches 80, even if none of the methods was directly reported. Reported methods should be broken down into several smaller methods. Reported classes should probably be broken down into subcomponents. CyclomaticComplexity (Priority: 3, Ruleset: Design) https://docs.pmd-code.org/snapshot/pmd_rules_java_design.html#cyclomaticcomplexity

Check warning on line 41 in src/main/java/fr/insalyon/creatis/gasw/executor/batch/BatchMonitor.java

View workflow job for this annotation

GitHub Actions / all

The method 'run()' has a cognitive complexity of 27, current threshold is 15

Methods that are highly complex are difficult to read and more costly to maintain. If you include too much decisional logic within a single method, you make its behavior hard to understand and more difficult to modify. Cognitive complexity is a measure of how difficult it is for humans to read and understand a method. Code that contains a break in the control flow is more complex, whereas the use of language shorthands doesn't increase the level of complexity. Nested control flows can make a method more difficult to understand, with each additional nesting of the control flow leading to an increase in cognitive complexity. Information about Cognitive complexity can be found in the original paper here: <https://www.sonarsource.com/docs/CognitiveComplexity.pdf> By default, this rule reports methods with a complexity of 15 or more. Reported methods should be broken down into less complex components. CognitiveComplexity (Priority: 3, Ruleset: Design) https://docs.pmd-code.org/snapshot/pmd_rules_java_design.html#cognitivecomplexity
while ( ! stop) {
verifySignaledJobs();
try {
Expand All @@ -50,12 +51,15 @@
if (status == GaswStatus.ERROR || status == GaswStatus.COMPLETED) {
daoJob.setExitCode(job.getExitCode());
daoJob.setStatus(job.getExitCode() == 0 ? GaswStatus.COMPLETED : GaswStatus.ERROR);
Map<JobMetric, String> metrics = job.generateRemoteMetrics();

Check warning on line 54 in src/main/java/fr/insalyon/creatis/gasw/executor/batch/BatchMonitor.java

View workflow job for this annotation

GitHub Actions / all

Local variable 'metrics' could be declared final

A local variable assigned only once can be declared final. LocalVariableCouldBeFinal (Priority: 3, Ruleset: Code Style) https://docs.pmd-code.org/snapshot/pmd_rules_java_codestyle.html#localvariablecouldbefinal
if (metrics != null) {
daoJob.setMetrics(metrics);
}

Check warning on line 57 in src/main/java/fr/insalyon/creatis/gasw/executor/batch/BatchMonitor.java

View workflow job for this annotation

GitHub Actions / all

Deeply nested if..then statements are hard to read

Avoid creating deeply nested if-then statements since they are harder to read and error-prone to maintain. AvoidDeeplyNestedIfStmts (Priority: 3, Ruleset: Design) https://docs.pmd-code.org/snapshot/pmd_rules_java_design.html#avoiddeeplynestedifstmts
} else {
daoJob.setStatus(status);
}

jobDAO.update(daoJob);
new BatchOutputParser(job).start();

Check warning on line 62 in src/main/java/fr/insalyon/creatis/gasw/executor/batch/BatchMonitor.java

View workflow job for this annotation

GitHub Actions / all

Avoid instantiating new objects inside loops

New objects created within loops should be checked to see if they can created outside them and reused. AvoidInstantiatingObjectsInLoops (Priority: 3, Ruleset: Performance) https://docs.pmd-code.org/snapshot/pmd_rules_java_performance.html#avoidinstantiatingobjectsinloops

} else if (status == GaswStatus.RUNNING) {
updateJob(daoJob, status);
Expand All @@ -63,27 +67,38 @@
}
Thread.sleep(GaswConfiguration.getInstance().getDefaultSleeptime());

} catch (GaswException | DAOException ex) {
log.error("Exception while monitoring batch jobs. Ignoring to continue the monitoring!", ex);
} catch (InterruptedException ex) {
log.error("Interrupted exception, stopping the worker!");
finish();
break;
}
catch (GaswException | DAOException ex) {
log.error("Exception while monitoring batch jobs. Ignoring to continue the monitoring!", ex);
} catch (InterruptedException ex) {
log.error("Interrupted exception, stopping the worker!");
finish();
break;
}
}
}

@Override
public synchronized void add(final String jobID, final String symbolicName, final String fileName, final String parameters) throws GaswException {
final Job job = new Job(jobID, GaswConfiguration.getInstance().getSimulationID(),
GaswStatus.QUEUED, symbolicName, fileName, parameters,
Constants.EXECUTOR_NAME);

public synchronized void add(

Check warning on line 82 in src/main/java/fr/insalyon/creatis/gasw/executor/batch/BatchMonitor.java

View workflow job for this annotation

GitHub Actions / all

Rather than using a lot of String arguments, consider using a container object for those values.

When you write a public method, you should be thinking in terms of an API. If your method is public, it means other class will use it, therefore, you want (or need) to offer a comprehensive and evolutive API. If you pass a lot of information as a simple series of Strings, you may think of using an Object to represent all those information. You'll get a simpler API (such as doWork(Workload workload), rather than a tedious series of Strings) and more importantly, if you need at some point to pass extra data, you'll be able to do so by simply modifying or extending Workload without any modification to your API. **Deprecated:** This rule is deprecated since PMD 7.26.0 and will be removed with PMD 8.0.0. Use {% rule ExcessiveParameterList %} instead. UseObjectForClearerAPI (Priority: 3, Ruleset: Design) https://docs.pmd-code.org/snapshot/pmd_rules_java_design.html#useobjectforclearerapi
final String jobID,
final String symbolicName,
final String fileName,
final String parameters) throws GaswException {

Job job = new Job();
job.setId(jobID);
job.setSimulationID(GaswConfiguration.getInstance().getSimulationID());
job.setStatus(GaswStatus.QUEUED);
job.setCommand(symbolicName);
job.setFileName(fileName);
job.setParameters(parameters);
job.setExecutor(Constants.EXECUTOR_NAME);
job.setQueued(new Date());

add(job);

log.info("Adding job: {}", jobID);
}

public synchronized void stopMonitor(boolean force) throws InterruptedException {
if (force) {
interrupt();
Expand Down Expand Up @@ -154,4 +169,4 @@

@Override
protected void resume(Job job) {}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import fr.insalyon.creatis.gasw.executor.batch.internals.commands.RemoteCommand;
import fr.insalyon.creatis.gasw.executor.batch.internals.commands.items.Qdel;
import fr.insalyon.creatis.gasw.executor.batch.internals.commands.items.Qsub;
import fr.insalyon.creatis.gasw.executor.batch.internals.commands.items.Sacct;
import fr.insalyon.creatis.gasw.executor.batch.internals.commands.items.Sbatch;
import fr.insalyon.creatis.gasw.executor.batch.internals.commands.items.Scancel;
import fr.insalyon.creatis.gasw.executor.batch.internals.commands.items.Scontrol;
Expand All @@ -14,39 +15,50 @@
@Slf4j
public enum BatchEngine {

SLURM(Sbatch.class, Scontrol.class, Scancel.class),
PBS(Qsub.class, Tracejob.class, Qdel.class);
SLURM(Sbatch.class, Scontrol.class, Scancel.class, Sacct.class),
PBS(Qsub.class, Tracejob.class, Qdel.class, null);
Comment thread
axlbonnet marked this conversation as resolved.
Resolved

final private Class<? extends RemoteCommand> submit;
final private Class<? extends RemoteCommand> status;
final private Class<? extends RemoteCommand> delete;
final private Class<? extends RemoteCommand> metrics;

BatchEngine(Class<? extends RemoteCommand> submitCommand, Class<? extends RemoteCommand> statusCommand,
Class<? extends RemoteCommand> deleteCommand) {
Class<? extends RemoteCommand> deleteCommand, Class<? extends RemoteCommand> metricsCommand) {
this.submit = submitCommand;
this.status = statusCommand;
this.delete = deleteCommand;
this.metrics = metricsCommand;
}

private RemoteCommand buidler(Class<? extends RemoteCommand> toBuild, final String data) {
try {
return toBuild.getConstructor(String.class).newInstance(data);
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException
| NoSuchMethodException e) {
log.error("Failed to build the command (using batch engines)", e);
private RemoteCommand builder(Class<? extends RemoteCommand> toBuild, final String data) {
if (toBuild == null) {
log.warn("No command class specified for this engine operation (data: {})", data);
return null;
}
try {
return toBuild.getConstructor(String.class).newInstance(data);
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException
| NoSuchMethodException e) {
log.error("Failed to build the command", e);
}
return null;
}
return null;
}

public RemoteCommand getSubmitCommand(final String data) {
return buidler(submit, data);
return builder(submit, data);
}

public RemoteCommand getStatusCommand(final String data) {
return buidler(status, data);
return builder(status, data);
}

public RemoteCommand getDeleteCommand(final String data) {
return buidler(delete, data);
return builder(delete, data);
}

public RemoteCommand getMetricsCommand(final String data) {
return builder(metrics, data);

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
if ( ! batchFile.exists()) {
batchFile.createNewFile();
}
try (FileOutputStream stream = new FileOutputStream(batchFile)) {

Check failure on line 40 in src/main/java/fr/insalyon/creatis/gasw/executor/batch/internals/BatchFileBuilder.java

View workflow job for this annotation

GitHub Actions / all

Avoid instantiating FileInputStream, FileOutputStream, FileReader, or FileWriter

The FileInputStream and FileOutputStream classes contains a finalizer method which will cause garbage collection pauses. See [JDK-8080225](https://bugs.openjdk.org/browse/JDK-8080225) for details. The FileReader and FileWriter constructors instantiate FileInputStream and FileOutputStream, again causing garbage collection issues while finalizer methods are called. * Use `Files.newInputStream(Paths.get(fileName))` instead of `new FileInputStream(fileName)`. * Use `Files.newOutputStream(Paths.get(fileName))` instead of `new FileOutputStream(fileName)`. * Use `Files.newBufferedReader(Paths.get(fileName))` instead of `new FileReader(fileName)`. * Use `Files.newBufferedWriter(Paths.get(fileName))` instead of `new FileWriter(fileName)`. Please note, that the `java.nio` API does not throw a `FileNotFoundException` anymore, instead it throws a `NoSuchFileException`. If your code dealt explicitly with a `FileNotFoundException`, then this needs to be adjusted. Both exceptions are subclasses of `IOException`, so catching that one covers both. AvoidFileStream (Priority: 1, Ruleset: Performance) https://docs.pmd-code.org/snapshot/pmd_rules_java_performance.html#avoidfilestream
stream.write(builder.toString().getBytes());
}
} catch (IOException e) {
Expand All @@ -61,7 +61,7 @@
.append(data.getCommand() + "\n")
.append("echo $? > " + data.getExitCodePath() + "\n");
}

private void doSlurm() {
builder.append("#!/bin/sh\n")
.append("#SBATCH --job-name=" + data.getJobID() + "\n")
Expand Down
Loading
Loading