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

remove and prevent asynchronous @postConstruct() functions #10423

Closed
paul-marechal opened this issue Nov 16, 2021 · 1 comment
Closed

remove and prevent asynchronous @postConstruct() functions #10423

paul-marechal opened this issue Nov 16, 2021 · 1 comment
Labels
quality issues related to code and application quality

Comments

@paul-marechal
Copy link
Member

paul-marechal commented Nov 16, 2021

For a bit of context, we need post-construct functions because of property injection. In order for Inversify to inject components into an instance's properties, the instance has to be constructed. This means that injected properties are not available until after the constructor has been called.

Inversify's instantiation logic may look something like this:

const argumentInjections = getArgumentInjections(ComponentClass);
// About to call the constructor...
const instance = new ComponentClass(...argumentInjections);
// Constructor finished, we have an instance we can inject properties into:
for (const [property, injection] of getPropertyInjections(ComponentClass)) {
  instance[property] = injection;
}
// Now the instance's properties are filled, time to run a user-defined hook to finalize the initialization of the instance:
instance[getPostConstructFunctionName(ComponentClass)]();
// The instance should be initialized and ready to be injected/used.

The key part is that Inversify doesn't await the post-construct function. Inversify APIs are mostly synchronous.

When we define asynchronous post-construct functions, what happens is that Inversify will just invoke it, wait for the synchronous part to run and then pass the instance around assuming it is fully initialized.

As a reminder, calling an asynchronous function from a synchronous function does execute part of its body:

async function asynchronous() {
  console.log('async 1');
  await new Promise(resolve => setTimeout(resolve, Math.PI * 1e11));
  console.log('async 2');
}

function synchronous() {
  console.log('sync 1');
  asynchronous();
  console.log('sync 2');
}

This will output the following:

sync 1
async 1
sync 2
// ~10 years later
async 2

This means that when Inversify calls our async post-construct functions, it will start passing the reference to our instance around right after the async function reaches its first await statement. This makes reasoning about our object's lifecycle difficult because some fields might be defined asynchronously but one might expect that Inversify waits for the post-constructor's promise to resolve.


We should remove and prevent asynchronous post-construct functions to better initialize our components.

@paul-marechal paul-marechal added the quality issues related to code and application quality label Nov 16, 2021
@msujew
Copy link
Member

msujew commented Jun 4, 2024

Closed with #12425. Async post construct functions now lead to errors on startup. All post construct methods are now sync.

@msujew msujew closed this as completed Jun 4, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
quality issues related to code and application quality
Projects
None yet
Development

No branches or pull requests

2 participants