Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add 'keep-alive' property to SpringApplication and document that it is useful when using virtual threads #37736

Closed
aahlenst opened this issue Oct 5, 2023 · 4 comments
Assignees
Labels
type: enhancement A general enhancement
Milestone

Comments

@aahlenst
Copy link
Contributor

aahlenst commented Oct 5, 2023

With platform threads, a method annotated with @Scheduled keeps an empty Spring Boot application running. When virtual threads are enabled, this is no longer the case and the application stops once it has initialized.

Example application (generated by Spring Initializr, Spring Boot 3.2.0-M3, no dependencies, Java 21):

@SpringBootApplication
@EnableScheduling
public class DemoApplication {

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

	@Scheduled(fixedDelay = 1000)
	public void run() {
		System.out.println("Running");
	}
}

With virtual threads enabled, there's only one line of "Running":

$ java -jar build/libs/demo-0.0.1-SNAPSHOT.jar --spring.threads.virtual.enabled=true 

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::             (v3.2.0-M3)

2023-10-05T18:37:14.740+02:00  INFO 96833 --- [           main] com.example.demo.DemoApplication         : Starting DemoApplication v0.0.1-SNAPSHOT using Java 21 with PID 96833 (/Users/andreas/Downloads/demo/build/libs/demo-0.0.1-SNAPSHOT.jar started by andreas in /Users/andreas/Downloads/demo)
2023-10-05T18:37:14.741+02:00  INFO 96833 --- [           main] com.example.demo.DemoApplication         : No active profile set, falling back to 1 default profile: "default"
2023-10-05T18:37:14.997+02:00  INFO 96833 --- [           main] com.example.demo.DemoApplication         : Started DemoApplication in 0.409 seconds (process running for 0.606)
Running
$ 

With virtual threads disabled, "Running" is printed until the application is stopped with CTRL+C:

$ java -jar build/libs/demo-0.0.1-SNAPSHOT.jar --spring.threads.virtual.enabled=false

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::             (v3.2.0-M3)

2023-10-05T18:37:05.777+02:00  INFO 96817 --- [           main] com.example.demo.DemoApplication         : Starting DemoApplication v0.0.1-SNAPSHOT using Java 21 with PID 96817 (/Users/andreas/Downloads/demo/build/libs/demo-0.0.1-SNAPSHOT.jar started by andreas in /Users/andreas/Downloads/demo)
2023-10-05T18:37:05.777+02:00  INFO 96817 --- [           main] com.example.demo.DemoApplication         : No active profile set, falling back to 1 default profile: "default"
Running
2023-10-05T18:37:06.037+02:00  INFO 96817 --- [           main] com.example.demo.DemoApplication         : Started DemoApplication in 0.411 seconds (process running for 0.612)
Running
Running
Running
Running
^C
$     

On the one hand, it makes sense because Spring Boot stops if there is not at least one non-daemon thread. On the other hand, it is no small change in behaviour. Is it intentional? If so, I could not find any mention in the reference or the release notes. The relevant entry is probably this one from the 3.2.0-M1 release notes about task execution.

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Oct 5, 2023
@philwebb philwebb added the for: team-attention An issue we'd like other members of the team to review label Oct 5, 2023
@philwebb
Copy link
Member

philwebb commented Oct 5, 2023

I'm not sure we'd consider it intentional, but it certainly makes sense given your description about non-daemon threads. We'll need to discuss it as a team to see what our options are.

@wilkinsona
Copy link
Member

We discussed this today. Our feeling was that there's nothing that we can do by default as it's very hard for us to know that the JVM should be kept alive through the existence of a non-daemon thread. If we get it wrong and someone isn't calling close() on the context to cause that thread to die, the JVM will never exit. The best alternative that we can think of is a configuration property to opt into a non-daemon thread being created for the sole purpose of keeping the JVM alive. That thread would stop running when the context is closed.

@aahlenst
Copy link
Contributor Author

aahlenst commented Oct 9, 2023

Thanks a lot for giving it a thought.

I'm primarily interested in it being documented because I wasn't sure whether I missed something. I doubt I'm going to be the only one.

Having an official mechanism to keep a Spring Boot application alive would be nice, especially because one of the popular workarounds (@Scheduled) no longer does the trick with virtual threads. An alternative could be better guidance what to do in those cases. Some technologies like servlet containers take care of it behind the scenes but others like RSocket clients do not.

@philwebb philwebb changed the title Scheduled does no longer keep application alive when virtual threads are enabled Add 'keep-alive' property to SpringApplication and document that it is useful when using virtual threads Oct 11, 2023
@philwebb philwebb added type: enhancement A general enhancement and removed for: team-attention An issue we'd like other members of the team to review status: waiting-for-triage An issue we've not yet triaged labels Oct 11, 2023
@philwebb philwebb modified the milestones: 3.x, 3.2.x Oct 11, 2023
@mhalbritter mhalbritter self-assigned this Oct 11, 2023
@mhalbritter mhalbritter modified the milestones: 3.2.x, 3.2.0-RC1 Oct 12, 2023
@mhalbritter
Copy link
Contributor

mhalbritter commented Oct 12, 2023

There's now the property spring.main.keep-alive. If set to true, it will spawn a non-daemon platform thread which keeps the JVM alive. This thread is stopped if the context is closed. I added some documentation around that, too.

wilkinsona added a commit that referenced this issue Oct 20, 2023
The current threads must be retrieved each time so that we can see
the keep-alive thread dying.

See gh-37736
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

5 participants