How to inject app/custom dependencies into PrometheusModule
Closed this issue ยท 6 comments
Hi there. Thank you very much for your work! So far everything is working great. However, I wanted to add a call to update gauges whenever the metrics are scraped. I thought I could use Custom Controller for this but I can't find a way to inject a dependency for my custom controller into the PrometheusModule.
Example
@Controller()
export class AppPrometheusController extends PrometheusController {
constructor(private readonly someService: SomeService) {
super();
}
@Get()
async index(@Res({ passthrough: true }) response: Response): Promise<string> {
await this.someService.updateGauges();
return super.index(response);
}
}
Usage
PrometheusModule.register({
controller: AppPrometheusController,
// can't put `providers` or `imports` here?
}),
Error
{"context":"ExceptionHandler","stack":["Error: Nest can't resolve dependencies of the AppPrometheusController (?).
Please make sure that the argument SomeService at index [0] is available in the PrometheusModule context.
Potential solutions:
- If SomeService is a provider, is it part of the current PrometheusModule?
- If SomeService is exported from a separate @Module, is that module imported within PrometheusModule?
...
I saw there is also registerAsync
, createAsyncProviders
and createAsyncOptionsProvider
but as they are not well documented, I'm not sure if they would be of any help.
Probably registerAsync
+ useFactory
is what you want. They are not documented here because they are fundamental NestJS concepts: https://docs.nestjs.com/fundamentals/async-providers
PrometheusModule.registerAsync
is not a NestJS concept. It requires me to define useClass
or useExisting
that want a Type<PrometheusOptionsFactory>
which I don't know how to construct. I tried looking through your tests but it doesn't fully make sense to me. I also don't see how it would solve my problem? I don't want to create the prometheus module / PrometheusOptions asynchronously but inject my dependency into the controller
.
Yes it is, it's a pattern used all over NestJS. Here is an example from an official module (name is different, concept is the same): https://docs.nestjs.com/graphql/quick-start#async-configuration
Check out the Custom Providers as well.
It would solve your problem because your controller would now be able to inject dependencies. So probably what you want here is some combination to create the controller outside of the PrometheusModule
context with whatever dependencies you need (async) and then you would PrometheusModule.registerAsync
to inject the controller.
This pattern is common to NestJS, true. But what @bijancn is referring to is PrometheusAsyncOptions is defined as
export interface PrometheusAsyncOptions extends Pick<ModuleMetadata, "imports"> {
useExisting?: Type<PrometheusOptionsFactory>;
useClass?: Type<PrometheusOptionsFactory>;
inject?: any[];
/** {@inheritDoc PrometheusOptions.controller} */
controller?: PrometheusOptions["controller"];
}
Which does not allow to use useFactory
:
TS2345: Argument of type '{ inject: (typeof ConfigService)[]; useFactory: (configService: ConfigService) => {...}' is not assignable to parameter of type 'PrometheusAsyncOptions'. Object literal may only specify known properties, and 'useFactory' does not exist in type 'PrometheusAsyncOptions'.
Which makes it impossible to use factory at this point.
Ah yes. Well at the time I wrote this, I couldn't find a way to get the result of useFactory
:
nestjs-prometheus/src/module.ts
Lines 90 to 100 in cc6e512
I can take a look again (or you are welcome to) since it really should be supported if possible.
๐ This issue has been resolved in version 5.3.0 ๐
The release is available on:
Your semantic-release bot ๐ฆ๐