NestJS object instantiation performance - nestjs

in NestJS, it is possible to define injection scope of injectable objects. (possibilities are: singleton, request, transient)
in the doc it is recommend to always use singleton scopes wherever possible, since f.e request scope will make nest instantiate providers on each request-response cycle, which can have an affect on the application's performance
Using request-scoped providers will have an impact on application performance. While Nest tries to cache as much metadata as possible, it will still have to create an instance of your class on each request. Hence, it will slow down your average response time and overall benchmarking result. Unless a provider must be request-scoped, it is strongly recommended that you use the default singleton scope.
Since when Object instantiation consumes so much resources?
that the entire framework is built around singleton instances,
making those instances kind of "state-full" in the sense where I can't really use "instance variable" safely, without the concern that 2 requests/consumers may use the same provider instance concurrently (due to the async nature of node) and conflict each other's instance variables?
here is what im trying to do:
export class MyClass {
constructor (...some dependencies) {
}
someMethod(payload){
this.myInstanceVariable = payload.data;
someMethod2();
}
someMethod2(){
// this.myInstanceVaraible usage, which i cant really trust it contains what i expect it to
}
}
I come from a ruby background.
when i wrote services in ruby, each request would instantiating whatever services it needs, and once the request was done, all those objects would be automatically garbage-collected.
that way i could safely define instance-variables on my services - without being concerned about
"instances conflicts".

NestJS supports injection scopes. There are provider scopes, controller scopes.
In your case if you need to use the instance variable with a provider, you might be able to use the REQUEST scope which would create a new object instance per request.
#Injectable({ scope: Scope.REQUEST })
export class CatsService {}
You can read more on this at https://docs.nestjs.com/fundamentals/injection-scopes

Related

NestJS: any way to create a provider for either a web-aware service, or a non web-aware service depending on context

Background
I'm working on a large application that needs to be upgraded. If I were starting from scratch I'd do this all differently. But right now I need to figure out a fix without touching hundreds of files.
For the same reason, I ideally need this code to work on Nest 6. This project needs to be upgraded to the latest nest, but there are some things that need to be fixed to do this. Before I can do that, I need to resolve the current issue, which is blocking us from upgrading off of node 12
Problem
I have a logger class. This class is supposed to pull in some information from the REQUEST context, if one is available (basically, some headers). If no request context is available, this can be ignored.
For simplicity in talking about this, we can say that I need a provider Logger which returns either a RequestAwareLogger or PlainLogger instance, depending on whether or not it is being resolved from a request scope. Alternately, I need the provider to return the same class, with either a request injected (via #Inject(REQUEST)), or left undefined.
Edit For posterity: If I were writing this from scratch, I'd just update the logger.log call to consume this information directly by passing in the request object, or the fields I needed tracked. But since this is a huge project already, I'd have to modify 1000 lines of code in different files, many of which don't have direct access to the request. This will be a longer term effort
Unfortunately, there is no built-in way to do this in Nest. However, it is possible to create a custom provider that would achieve the same effect.
Here is an example provider that would return either a RequestAwareLogger or PlainLogger instance, depending on whether or not it is being resolved from a request scope:
#Injectable()
export class LoggerProvider {
constructor(
#Optional() #Inject(REQUEST) private readonly request?: Request,
) {}
getLogger(): PlainLogger | RequestAwareLogger {
// If a request is available, return a RequestAwareLogger instance
if (this.request) {
return new RequestAwareLogger(this.request);
}
// Otherwise, return a PlainLogger instance
return new PlainLogger();
}
}
Then, you can use this provider in your logger service like so:
#Injectable()
export class LoggerService {
constructor(private readonly loggerProvider: LoggerProvider) {}
log(message: string) {
const logger = this.loggerProvider.getLogger();
// Use the logger instance
logger.log(message);
}
}
Note that this provider will only work if Nest's IoC container is used to resolve the logger service. If you are using a different IoC container (e.g. in a non-Nest application), you will need to create a custom provider for that container.

what is getRepositoryToken in nestjs typeorm and when to use it?

The docs here are as below:
When it comes to unit testing an application, we usually want to avoid
making a database connection, keeping our test suites independent and
their execution process as fast as possible. But our classes might
depend on repositories that are pulled from the connection instance.
How do we handle that? The solution is to create mock repositories. In
order to achieve that, we set up custom providers. Each registered
repository is automatically represented by a Repository
token, where EntityName is the name of your entity class.
The #nestjs/typeorm package exposes the getRepositoryToken() function
which returns a prepared token based on a given entity.
What does that even mean? Autocomplete docs just give the signature with no explanation.
getRepositoryToken() is a helper method that allows you to get the same injection token that #InjectRepository() returns. This is useful when it comes to tests so that you can define a custom provider that has a matching token for the DI resolution, and so you can provide a mock of the Repository methods without the need to actually talk to the database. So for example, if you have
#Injectable()
export class FooService {
constructor(#InjectRepository(Foo) private readonly fooRepo: Repository<Foo>) {}
}
In your test you can add the provider
{
provide: getRepositoryToken(Foo),
useValue: {
find: jest.fn(),
insert: jest.fn(),
},
}
And now you've got a mock injectable provider for the Repository.
The biggest reason that things have to be done this way is because typescript doesn't reflect generic classes, it only reflects Repository, and if Nest tries to figure out which repository you mean to inject, with just that name (Repository) it's most likely going to get it wrong and inject the wrong class. Using #InjectRepsitory() allows for setting the proper injection token.

ASP.NET Core Scoped DbContext (EntityFramework) in Multithreading Environment

I read a lot about a scoped DbContext (EntityFramework) in a ASP.NET Core environment.
It makes sense to setup the DI framework with a scoped DbContext, due to have one DbContext per request.
Unfortunately this DbContext cannot be used in a Parallel.ForEach loop (or any kind of thread). The DbContext itself is not threadsafe! So I have to be careful using any kind of Task/Thread.
But sometimes its necessary (or useful) to implements something in a Parallel.ForEach (or something like this).
But how can I be sure that my called functions in a Parallel.ForEach dont use any kind of DbContext? Or maybe one day I decide to use a DbContext in some class/functions which is called from a Task, but I dont not recognize it?
There must be a solution for this? Right now it seems that I cannot use the TPL at all (just to be safe) ... but this seems to be very strange.
Isn't there any better approach?
You would have to inject a IServiceProvider and create your own scope for each iteration.
A quick example would look like
Parallel.ForEach(values, value =>
{
using (var scope = _serviceProvider.CreateScope())
{
var context = scope.ServiceProvider.GetRequiredService<DbContext>();
//query context here
} // The context will be disposed off by the scope
});
Serviced acquired through the scope will also be scoped to it (when applicable)

autofac and multithreading

when doing parallel/multithreading, if there are dependencies that are not thread safe, what kind of instance method can be used with autofac to get an instance per thread? from what I know, autofac is the kind of DI container for certain framework like asp.net/mvc but for the rest of the app type like windows service, it does not have any support. in my scenario, i am doing multithreading for a windows service that also hosting a web api service. what kind of registration can be used so that it will work for web api instanceperhttprequest and instanceperlifetimescope. two separate container?
EDIt:
using this parallel extension method here:
public static Task ForEachAsync<T>(this IEnumerable<T> source, int dop, Func<T, Task> body)
{
return Task.WhenAll(
from partition in Partitioner.Create(source).GetPartitions(dop)
select Task.Run(async delegate
{
using (partition)
{
while (partition.MoveNext())
{
await body(partition.Current);
}
}
}));
}
so the body will be use to do the work. DI will need to be inside of the body func.
It doesn't matter what kind of application you run; the pattern is always the same. You should resolve one object graph per request. In a web application, a request means a web request, in a windows service, a request is usually a timer pulse.
So in a windows service, each 'pulse' you start a new lifetime scope, and within this scope you resolve your root object and call it.
If however, you process items in parallel within a single request, you should see each processed item as a request of its own. So that means that on each thread you should start a new lifetime scope and resolve a sub object graph from that scope and execute that. Prevent passing services that are resolved from your container, from thread to thread. This scatters the knowledge of what is thread-safe, and what isn't throughout the application, instead of keeping that knowledge centralized in the startup path of your application where you compose your object graphs (the composition root).
Take a look at this article about working with dependency injection in multi-threaded applications. It's written for a different DI library, but you'll find most of the advice generically applicable to all DI libraries.

How would you inject and handle a database object from an object pool into a resource?

i've been thinking about implementing a object pool for jcouchdb objects for jersey. Now i am asking myself what would be the best way to deliver a jcouchdb instance to the resource endpoints.
I expect the pool to have a method for requesting an jcouchdb object and for releasing it so that it can be reused.
My first idea was to implement a InjectableProvider as a singleton an use a annotation in the resource endpoint to "grab" it. The InjectableProvider then returns an jcouchdb object from the object pool and marks it as busy. How can i release the jcouchdb object after I've used it? And i would request a jcouchdb object for every resource endpoint instance even if i never need it?! (don't know when the annotated objects get instantiated)
Another idea i was thinking about was to attach the object pool to the servlet context (with set attribute).
Any other ideas?
I am basically a bit confused when i comes to shared resources and jersey. Hopefully someone can clear things up for me.
Thanks
If you do exactly as you just said, your code would look like this:
public class MyResource{
#GET
#RequestMapping("/bleh")
public Response getValue(#Context JCouchDBObject object){
//manipulate object
}
}
#Provider
public class MyProvider extends InjectableProvider<Context, Parameter>{
public Injectable<JCouchDBObject> getInjectable(ComponentContext context, Context hp, Parameter param) {
//GetObject and return
}
}
I've never worked with JCouchDB, but unless each object is linked to the DB connection pool - there is nothing to manually release - all of this will be handled for you.
But: This is not what the InjectableProvider was designed for. Typically, the InjectableProvider will be used to create and resolve some sort of request object (such as the JCouchDBObject's ID, etc). Then you should use a service to collect the JCouchDBObject and handling any manually release there.

Resources