Skip to content

StartupStep are closed twice in SpringApplicationRunListeners #22776

Closed
@mdeinum

Description

@mdeinum

With the introduction of #22600 I was eager to test this with Flight Recorder based events. For this purpose, I cloned the Petclinic, updated it to Spring Boot 2.4.0-SNAPSHOT and confined it to run using the FlightRecorderApplicationStartup. However, when doing so it results in an exception during startup.

xception in thread "restartedMain" java.lang.reflect.InvocationTargetException
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49)
Caused by: java.util.NoSuchElementException
	at java.base/java.util.ArrayDeque.getFirst(ArrayDeque.java:403)
	at org.springframework.core.metrics.jfr.FlightRecorderApplicationStartup.start(FlightRecorderApplicationStartup.java:52)
	at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:111)
	at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:106)
	at org.springframework.boot.SpringApplicationRunListeners.environmentPrepared(SpringApplicationRunListeners.java:57)
	at org.springframework.boot.SpringApplication.prepareEnvironment(SpringApplication.java:356)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:318)
	at org.springframework.samples.petclinic.PetClinicApplication.main(PetClinicApplication.java:39)
	... 5 more

The events that are logged are

  1. spring.boot.application.starting, sequenceId = 0
  2. spring.boot.application.starting (?), sequenceId = 0
  3. spring.boot.application.environment-prepared, sequenceId = 1
  4. spring.boot.application.failed , sequenceId = 2 -> which leads to the error due to the currentSteps Deque is empty.

EDIT (1): The second spring.boot.application.starting event appears to be the result of including spring-boot-devtools as a dependency. Which I thought might be the culprit, however even without Devtools the applications breaks.

To reproduce checkout petclinic, upgrade Spring Boot and use the following PetClinicApplication class

@SpringBootApplication(proxyBeanMethods = false)
public class PetClinicApplication {

	public static void main(String[] args) {
		SpringApplication springApplication = new SpringApplicationBuilder()
			.applicationStartup(new FlightRecorderApplicationStartup())
			.sources(PetClinicApplication.class)
			.build();
		springApplication.run(args);
	}
}

The application starts successfully when commenting the .applicationStartup(new FlightRecorderApplicationStartup()) line.

Parameters used to start the application with JFR metrics -XX:StartFlightRecording:filename=recording.jfr,duration=10s

After some debugging it appears that the error is this the doWithListeners method in the SpringApplicationRunListeners class.

EDIT (2)

private void doWithListeners(String stepName, Consumer<SpringApplicationRunListener> listenerAction) {
	doWithListeners(stepName, listenerAction, StartupStep::end);
}

private void doWithListeners(String stepName, Consumer<SpringApplicationRunListener> listenerAction,
		Consumer<StartupStep> stepAction) {
	StartupStep step = this.applicationStartup.start(stepName);
	this.listeners.forEach(listenerAction);
	stepAction.accept(step);
	step.end();
}

The lambda passed into stepAction results in the StartupStep.end method being invoked twice, leading to exhausting the Deque.

Relates to: #22600

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions