@Async

@Async

@Async marks a command method to run asynchronously (on a separate thread) instead of the main thread. By default, command methods execute synchronously — the calling thread is blocked until the method finishes. When you add @Async, Imperat runs the method on a background thread using ForkJoinPool.commonPool(), so the main thread is free to continue.

When to Use

  • When your command does slow work like database queries, HTTP requests, or file I/O.
  • When the command logic is non-critical and doesn't need to block the caller.

Where to Place

On a method annotated with @Execute.

@Target(ElementType.METHOD)

Example





@RootCommand("balance")
public class BalanceCommand {

    @Execute
    @Async
    public void checkBalance(PLATFORMSOURCE source) {
        // This runs on a background thread, not the main thread.
        // Safe to do slow database lookups here.
        double balance = database.getBalance(source.name());
        source.reply("Your balance: $" + balance);
    }
}

Without @Async: The method blocks the main thread until database.getBalance(...) finishes.
With @Async: The method runs in the background through ForkJoinPool.commonPool(). The main thread returns immediately.

The default ForkJoinPool.commonPool() is shared across the entire application, so be mindful of how many async tasks you run to avoid overwhelming it. If you need more control, consider using a custom ExecutorService (see below).

Custom ExecutorService

You can specify a custom ExecutorService to supply your custom thread/thread-pool for async execution. This is useful if you want to manage your own threads or use a different thread pool. Just create a class that implements ExecutorServiceProvider.

public class CustomExecutorProvider implements ExecutorServiceProvider {
    private final ExecutorService executor = Executors.newFixedThreadPool(10);

    @Override
    public ExecutorService provideExecutorService() {
        return executor;
    }
}

Then declare it in your @Async annotation:

@Async(CustomExecutorProvider.class)

If your custom ExecutorService requires parameters in its constructor, you MUST inject its instance through imperat's dependency injection system. For more details read the Dependency Injection documentation.

Important Notes

  • The annotation takes no parameters. Just add @Async and you're done.
  • Be careful with thread safety — don't access non-thread-safe objects from async methods.
  • Async methods may finish after the command call returns to the sender.