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 Async Bean Generation #736

Closed
wants to merge 13 commits into from
Closed

Conversation

SentryMan
Copy link
Collaborator

First crack at #735

given a class

@Singleton
@AsyncBean
public class BackgroundBean {
  @Inject Provider<Integer> intProvider;
}

the following will generate

@Generated("io.avaje.inject.generator")
public final class BackgroundBean$DI  {

  public static void build(Builder builder) {
    if (builder.isAddBeanFor(BackgroundBean.class)) {
      builder.registerProvider(CompletableFuture.supplyAsync(() -> {
        var bean = new BackgroundBean();
        bean.intProvider = builder.getProvider(Integer.class);
        return bean;
      })::join);  //use join to turn this future into a Provider 
    }
  }
}

@SentryMan SentryMan added the enhancement New feature or request label Nov 17, 2024
@SentryMan SentryMan self-assigned this Nov 17, 2024
@SentryMan SentryMan marked this pull request as ready for review November 18, 2024 14:09
@SentryMan
Copy link
Collaborator Author

what should be the annotation's name?

  • @Async
  • @AsyncBean
  • @Background

@SentryMan SentryMan requested a review from rbygrave November 18, 2024 22:15
…ponent

Once we have a component that depends on a Async component that all needs to resolve when creating the BeanScope.
@rbygrave
Copy link
Contributor

I'm wondering how practical this is in real life?

Once we have a component that depends on an async component the BeanScope needs to wait for the CompletableFuture to finish etc. That is, as soon as the "slow" components you might want this on have components that depend on them it quickly hits that wait.

Seems to me the use case is something that is "slow" that also doesn't have many components that depend on it? What would real life examples of this be?

Lazy seems like the better option for the "relatively expensive" components (like Desktop UI components) for on demand lazy creation use case.

@SentryMan
Copy link
Collaborator Author

Lazy seems like the better option for the "relatively expensive" components (like Desktop UI components) for on demand lazy creation use case.

well the one situation it might be useful is when the async component is also retrieved lazily.

suppose I had a bean like this:

@AsyncBean
@Component
public class MyUseOfBackground {

  private final BackgroundBean backgroundBean;

  public MyUseOfBackground(@Named("single") BackgroundBean backgroundBean) {
    this.backgroundBean = backgroundBean;
  }
}

then used it like this:

@Component
public class UseBackground {

  private final Provider<MyUseOfBackground> backgroundBeanProv;

  public UseBackground(Provider<MyUseOfBackground> backgroundBeanProv) {
    this.backgroundBeanProv = backgroundBeanProv;
  }
}

in a case like this, the MyUseOfBackground is being prepared in the background so that when the backgroundBeanProv is actually called, it can be immediately ready instead of needing to wait a second for the bean to initialize.

@SentryMan
Copy link
Collaborator Author

hmm, perhaps it should be an option of the @Lazy annotation rather than it's own annotation

@rbygrave
Copy link
Contributor

rbygrave commented Nov 19, 2024 via email

@rbygrave
Copy link
Contributor

rbygrave commented Nov 19, 2024 via email

@SentryMan
Copy link
Collaborator Author

I should check the spring issue related to this.

Apparently, it's one of the most voted issues ever: spring-projects/spring-framework#13410

@rbygrave
Copy link
Contributor

Apparently, it's one of the most voted issues ever

We have to be a little bit careful though because:

  • some people are nuts
  • some of those cases are ... "self inflicted" / avoidable
  • some of this is down to the Spring DI specific mechanism and not actually applicable to avaje-inject.

Parallelize Component Scanning to Improve Spring Startup Time

avaje-inject avoids scanning altogether PLUS has already ordered the dependency wiring so yes we are a lot faster than Spring DI due to that. For myself, I also use libraries that also can avoid classpath scanning (Ebean ORM, ebean-migrations ... so no scanning and no dynamic proxies).

In the past I have been here though in terms of a Spring app starting up in around 30+ seconds. In a large modular application (not microservices, more "modular monolith") people can "feel" the startup time with Spring but again I'm saying we don't actually have this at all with avaje-inject because we don't have any scanning or any dynamic proxies.

So I'd say that slow startup time in an avaje-inject app is going to come from specific network activities (like obtaining remote configuration secrets/properties, initialising datasources, running database migrations, initialising queuing clients, populating caches on startup).

we have a startup time of out complete production environment of ~2h 30 Minutes.

That's just nuts and also provides zero detail as to what is actually slow.

Background initialization option for JPA EntityManagerFactory / Hibernate SessionFactory

That's due to Hibernate's use of classpath scanning and dynamic proxies. I don't have a lot of sympathy for people who do this to be honest.

@SentryMan
Copy link
Collaborator Author

Seems like a solution in search of a problem. Closing unless somebody actually needs it.

@SentryMan SentryMan closed this Nov 19, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants