> Markdown version of [Background Jobs](https://vaadin.com/docs/next/building-apps/business-logic/background-jobs). Section index: [llms.txt](https://vaadin.com/docs/next/building-apps/llms.txt)

# Background Jobs Deep Dive

Many business applications need to perform in background threads. These tasks might be long-running operations triggered by the user, or scheduled jobs that run at specific times or intervals.

Working with more than one thread increases the risk of bugs. Furthermore, there are many different ways of implementing background jobs. To reduce the risk, you should learn one way, and then apply it consistently in all of your Vaadin applications.

> **Important: Deep Dive - Recommended Approach**
>
> This **opinionated** deep-dive explains core concepts (for example, task executors in Spring) and gives a practical, recommended way to handle background jobs in Vaadin. If you’re new, this is a good place to start; if you’re experienced, feel free to use whatever patterns work for you.

## <a id="threads"></a>Threads

Whenever you work with background threads in a Vaadin application, you should never create new `Thread` objects, directly. First, new threads are expensive to start. Second, the number of concurrent threads in a Java application is limited. While the exact limit depends on various factors, Java applications typically support thousands of threads.

Instead of creating threads manually, you should use either a thread pool, or virtual threads.

A thread pool consists of a queue, and a pool of running threads. The threads pick tasks from the queue and execute them. When the thread pool receives a new job, it adds it to the queue. The queue has an upper size limit. If the queue is full, the thread pool rejects the job, and throws an exception.

Virtual threads were added in Java 21. Whereas ordinary threads are managed by the operating system, virtual threads are managed by the Java virtual machine. They’re cheaper to start and run, which means you can have a much higher number of concurrent virtual threads than ordinary threads. If your virtual machine supports virtual threads, you should use them.

For more information on virtual threads, see the [Java Documentation](https://docs.oracle.com/en/java/javase/21/core/virtual-threads.html).

## <a id="task-execution"></a>Task Execution

The background jobs themselves shouldn’t need to manage their own thread pools, or virtual threads. Instead, they should use *executors*. An executor is an object that takes a `Runnable`, and executes it at some point in the future. Spring provides a `TaskExecutor`, that you should use in your background jobs.

By default, Spring Boot sets up a `ThreadPoolTaskExecutor` in your application context. You can tweak the parameters of this executor through the `spring.task.executor.*` configuration properties.

To use virtual threads, you can enable them by setting the `spring.threads.virtual.enabled` configuration property to `true`. In this case, Spring Boot sets up a `SimpleAsyncTaskExecutor`, and creates a new virtual thread for every task.

You can interact with the `TaskExecutor` either directly, or declaratively through annotations.

When interacting with it directly, you would inject an instance of `TaskExecutor` into your code, and submit work to it.

Here is an example of a class that uses the `TaskExecutor`:

```java
import org.springframework.core.task.TaskExecutor;

@Service
public class MyWorker {

    private final TaskExecutor taskExecutor;

    MyWorker(TaskExecutor taskExecutor) {
        this.taskExecutor = taskExecutor;
    }

    public void performTask() {
        taskExecutor.execute(() -> {
            System.out.println("Hello, I'm running inside thread " + Thread.currentThread());
        });
    }
}
```

> **Important:** When you inject the `TaskExecutor`, you have to name the parameter `taskExecutor`. The application context may contain more than one bean that implements the `TaskExecutor` interface. If the parameter name doesn’t match the name of the bean, Spring doesn’t know which instance to inject.

If you want to use annotations, you have to enable them first. Do this by adding the `@EnableAsync` annotation to your main application class, or any other `@Configuration` class.

Here’s an example that adds the annotation to the main application class:

```java
import org.springframework.scheduling.annotation.EnableAsync;

@SpringBootApplication
@EnableAsync
public class Application{

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

You can now use the `@Async` annotation to tell Spring to execute your code in a background thread.

Here is a version of the earlier `MyWorker` example, but using `@Async` instead of the `TaskExecutor`:

```java
import org.springframework.scheduling.annotation.Async;

@Service
public class MyWorker {

    @Async
    public void performTask() {
        System.out.println("Hello, I'm running inside thread " + Thread.currentThread());
    }
}
```

For more information about task execution, see the [Spring Documentation](https://docs.spring.io/spring-framework/reference/integration/scheduling.html).

### <a id="task-execution-annotation-caveats"></a>Task Execution Annotation Caveats

Using annotations makes the code more concise. However, they come with some caveats.

Should you forget to add `@EnableAsync` to your application, your `@Async` methods run synchronously in the calling thread instead of in a background thread. Also, you can’t call an `@Async` method from within the bean itself. This is because Spring by default uses proxies to process `@Async` annotations, and local method calls bypass the proxy.

In the following example, `performTask()` is executed in a background thread, and `performAnotherTask()` in the calling thread:

```java
@Service
public class MyWorker {

    @Async
    public void performTask() {
        System.out.println("Hello, I'm running inside thread " + Thread.currentThread());
    }

    public void performAnotherTask() {
        performTask(); // This call runs in the calling thread
    }
}
```

If you interact directly with `TaskExecutor`, you’ll avoid this problem. In the following example, both `performTask()` and `performAnotherTask()` execute in a background thread:

```java
@Service
public class MyWorker {

    private final TaskExecutor taskExecutor;

    MyWorker(TaskExecutor taskExecutor) {
        this.taskExecutor = taskExecutor;
    }

    public void performTask() {
        taskExecutor.execute(() -> {
            System.out.println("Hello, I'm running inside thread " + Thread.currentThread());
        });
    }

    public void performAnotherTask() {
        performTask(); // This method executes its task in a background thread
    }
}
```

## <a id="task-scheduling"></a>Task Scheduling

Spring also has built in support for scheduling tasks through a `TaskScheduler`. You can interact with it either directly, or through annotations. With both, you have to enable it by adding the `@EnableScheduling` annotation to your main application class, or any other `@Configuration` class.

Below is an example that adds the annotation to the main application class:

```java
import org.springframework.scheduling.annotation.EnableScheduling;

@SpringBootApplication
@EnableScheduling
public class Application{

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

When interacting directly with the `TaskScheduler`, you’d inject it into your code, and schedule work with it.

This is an example that uses the `TaskScheduler` to execute the `performTask()` method every five minutes:

```java
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.scheduling.TaskScheduler;

@Service
class MyScheduler implements ApplicationListener<ApplicationReadyEvent> {

    private final TaskScheduler taskScheduler;

    MyScheduler(TaskScheduler taskScheduler) {
        this.taskScheduler = taskScheduler;
    }

    @Override
    public void onApplicationEvent(ApplicationReadyEvent event) {
        taskScheduler.scheduleAtFixedRate(this::performTask, Duration.ofMinutes(5));
    }

    private void performTask() {
        System.out.println("Hello, I'm running inside thread " + Thread.currentThread());
    }
}
```

You can achieve the same using the `@Scheduled` annotation, like this:

```java
import org.springframework.scheduling.annotation.Scheduled;

@Service
class MyScheduler {

    @Scheduled(fixedRate = 5, timeUnit = TimeUnit.MINUTES)
    public void performTask() {
        System.out.println("Hello, I'm running inside thread " + Thread.currentThread());
    }
}
```

For more information about task scheduling, see the [Spring Documentation](https://docs.spring.io/spring-framework/reference/integration/scheduling.html).

### <a id="task-scheduling-caveats"></a>Task Scheduling Caveats

Spring uses a separate thread pool for task scheduling. The tasks themselves are also executed in this thread pool. That’s fine if you have a small number of short tasks. However, if you have many tasks, or long-running tasks, you may have problems. For instance, your scheduled jobs might stop running because the thread pool has become exhausted.

To avoid trouble, you should use the scheduling thread pool to schedule jobs. Then give them to the task execution thread pool to execute. You can combine the `@Async` and `@Scheduled` annotations, like this:

```java
@Service
class MyScheduler {

    @Scheduled(fixedRate = 5, timeUnit = TimeUnit.MINUTES)
    @Async
    public void performTask() {
        System.out.println("Hello, I'm running inside thread " + Thread.currentThread());
    }
}
```

You can also interact directly with the `TaskScheduler` and `TaskExecutor`, like this:

```java
@Service
class MyScheduler implements ApplicationListener<ApplicationReadyEvent> {

    private final TaskScheduler taskScheduler;
    private final TaskExecutor taskExecutor;

    MyScheduler(TaskScheduler taskScheduler, TaskExecutor taskExecutor) {
        this.taskScheduler = taskScheduler;
        this.taskExecutor = taskExecutor;
    }

    @Override
    public void onApplicationEvent(ApplicationReadyEvent event) {
        taskScheduler.scheduleAtFixedRate(this::performTask, Duration.ofMinutes(5));
    }

    private void performTask() {
        taskExecutor.execute(() -> {
            System.out.println("Hello, I'm running inside thread " + Thread.currentThread());
        });
    }
}
```

## <a id="topics"></a>Topics

The following pages show how to implement background jobs, how to trigger them, and how to show their progress and results in the user interface.

- [Implementing Jobs](https://vaadin.com/docs/next/building-apps/business-logic/background-jobs/jobs.md): How to implement background jobs.
- [Triggering Jobs](https://vaadin.com/docs/next/building-apps/business-logic/background-jobs/triggers.md): How to trigger background jobs.
- [UI Interaction](https://vaadin.com/docs/next/building-apps/business-logic/background-jobs/interaction.md): How to interact with jobs from the user interface.
