Skip to content

Conversation

@Yavor16
Copy link
Contributor

@Yavor16 Yavor16 commented Jan 5, 2026

No description provided.

@Yavor16 Yavor16 force-pushed the application-shutdown-logic-update branch from 0642e66 to 31b61f2 Compare January 5, 2026 09:24
LMCROSSITXSADEPLOY-3344

# Conflicts:
#	multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/Messages.java
@Yavor16 Yavor16 force-pushed the application-shutdown-logic-update branch from 31b61f2 to 8da103c Compare January 5, 2026 09:25
@sonarqubecloud
Copy link

sonarqubecloud bot commented Jan 5, 2026

Quality Gate Failed Quality Gate failed

Failed conditions
0.0% Coverage on New Code (required ≥ 80%)

See analysis details on SonarQube Cloud

return ImmutableApplicationShutdown.builder()
.id(UUID.randomUUID()
.toString())
.staredAt(Date.from(Instant.now()))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

staredAt or startedAt? Is there a typo?

public static final String APP_SHUTDOWNED = "Application with id:\"{0}\", instance id:\"{1}\", instance index:\"{2}\", is shutdowned. Timeout to wait before shutdown of Flowable job executor:\"{3}\" seconds.";
public static final String APP_SHUTDOWN_STATUS_MONITOR = "Monitor shutdown status of application with id:\"{0}\", instance id:\"{1}\", instance index:\"{2}\". Status:\"{3}\".";
public static final String APP_SHUTDOWN_STATUS_MONITOR = "Monitor shutdown status of application with id:\"{0}\"";
public static final String APP_INSTANCE_WITH_ID_AND_INDEX_SCHEDULED_FOR_DELETION = "Application with ID \"{0}\" and index \"{1}\" has been scheduled for deletion";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't be scheduled for stop/shutdown?

@@ -0,0 +1,56 @@
package org.cloudfoundry.multiapps.controller.core.application.shutdown;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't it better to keep all logic related to shutdown in the separate java package/maven submodule?

@Value.Default
default Status getStatus() {
return Status.RUNNING;
default String getStatus() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why don't preserve return of enum object instead of string?

import jakarta.persistence.TemporalType;

@Entity
@Table(name = "application_shutdown")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extract as constants into PersistenceMetadata

}

public static boolean isTimeoutExceeded(ApplicationShutdown applicationShutdown) {
Instant thirtyMinutesAfterStartedDate = Instant.from(applicationShutdown.getStaredAt()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How this is 30 minutes after start when timeout constant says 10 minutes?

return timeNow.isAfter(thirtyMinutesAfterStartedDate);
}

public static void print(List<ApplicationShutdown> shutdown) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you name the method with more meaningful name - for example printShutdownStatus or logShutdownStatus. Also name shutdown variable to include instances in the name.

instanceShutdownExecutor.execute(applicationGuid, i);
public void execute(String applicationId, int applicationInstanceCount) {
ApplicationShutdownScheduler applicationShutdownScheduler = getApplicationShutdownScheduler();
List<ApplicationShutdown> scheduledApplicationShutdowns = applicationShutdownScheduler.scheduleApplicationForShutdown(applicationId,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What will happen if count of instances is mistaken or some of existing instances are in crashed/not running state? Will it lead to infinite loop?

import jakarta.inject.Inject;

@RestController
@RequestMapping(value = Constants.Resources.APPLICATION_SHUTDOWN)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you delete all related constants?

<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>${servlet-api.version}</version>
<scope>provided</scope>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this dependency is now included as part of the war file? Isn't it provided by the java buildpack?

int applicationIndex = configuration.getApplicationInstanceIndex();
ApplicationShutdown applicationShutdown = applicationShutdownService.getApplicationsByApplicationIndex(applicationIndex);
if (applicationShutdown != null) {
LOGGER.info(org.cloudfoundry.multiapps.controller.core.Messages.CLEARING_OLD_ENTRY + applicationIndex);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use here MessageFormat.format instead of concatenation

List<String> instancesIds) {
List<ApplicationShutdown> instances = new ArrayList<>();
for (String instanceId : instancesIds) {
instances.add(applicationShutdownService.getApplicationShutdownInstanceByInstanceId(instanceId, applicationId));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this return null?

Comment on lines +59 to +61
public ApplicationShutdown updateApplicationShutdownStatus(ApplicationShutdown oldApplicationShutdown, String status) {
ApplicationShutdown newApplicationShutdown = ImmutableApplicationShutdown.copyOf(oldApplicationShutdown)
.withStatus(status);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe enum for status instead of String

Comment on lines +32 to +44

@Column(name = "application_instance_index", nullable = false, unique = true)
private int applicationInstanceIndex;

@Column(name = "application_id", nullable = false)
private String applicationId;

@Column(name = "shutdown_status", nullable = false)
private String shutdownStatus;

@Column(name = "started_at", nullable = false)
@Temporal(TemporalType.TIMESTAMP)
private Date startedAt;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extract as constants

}

@Override
public ApplicationShutdown singleResult() throws NoResultException, NonUniqueResultException {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't this method return null, why throw NoResultException

Comment on lines +40 to +41
if (applicationShutdown == null || applicationShutdown.getStatus()
.equals(Status.FINISHED.name())) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here use directly the enum instead of string

Comment on lines +69 to +75
private void shutdownApplication(ApplicationShutdown applicationShutdown) {
CompletableFuture.runAsync(() -> {
logProgressOfShuttingDown(applicationShutdown, Messages.SHUTTING_DOWN_APPLICATION_WITH_ID_AND_INDEX);
flowableFacade.shutdownJobExecutor();
})
.thenRun(() -> logProgressOfShuttingDown(applicationShutdown, Messages.SHUT_DOWN_APPLICATION_WITH_ID_AND_INDEX));
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible here, exception to be thrown inside the async task, this will impact the DB state in a wrong way. Maybe add FAILED status for such cases.

@stiv03
Copy link
Contributor

stiv03 commented Jan 8, 2026

Also add some unit tests, cause now there is 0.0% Coverage on New Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants