Skip to content

Commit

Permalink
feat: allow for microservice options to come from the di container
Browse files Browse the repository at this point in the history
Microservices are now able to be created by getting their options
from within the DI container itself. This has been a long requested
feature of developers and I finally had some time to work through how
we could possibly let this happen.
  • Loading branch information
jmcdo29 committed Oct 20, 2023
1 parent ecdd86f commit 7ed071d
Show file tree
Hide file tree
Showing 3 changed files with 130 additions and 8 deletions.
98 changes: 98 additions & 0 deletions integration/microservices/e2e/sum-rpc-async.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import {
Controller,
INestMicroservice,
Injectable,
Module,
} from '@nestjs/common';
import {
AsyncOptions,
ClientTCP,
ClientsModule,
MessagePattern,
MicroserviceOptions,
Payload,
TcpClientOptions,
Transport,
} from '@nestjs/microservices';
import { expect } from 'chai';
import { NestFactory } from '@nestjs/core';

let port: number;

do {
port = Math.round(Math.random() * 10000);
} while (port < 1000);

@Injectable()
class RpcOptionsProvider {
getOptions(): TcpClientOptions {
return {
transport: Transport.TCP,
options: {
port,
host: '0.0.0.0',
},
};
}
}

@Controller()
class RpcController {
@MessagePattern({ cmd: 'sum' })
sumPayload(@Payload() payload: number[]) {
return payload.reduce((a, b) => a + b, 0);
}
}

@Module({
imports: [
ClientsModule.register([
{
name: 'RPC_CLIENT',
transport: Transport.TCP,
options: {
port,
host: '0.0.0.0',
},
},
]),
],
controllers: [RpcController],
providers: [RpcOptionsProvider],
})
class RpcModule {}

describe('RPC Async transport', () => {
let app: INestMicroservice;
let client: ClientTCP;

beforeEach(async () => {
app = await NestFactory.createMicroservice<
AsyncOptions<MicroserviceOptions>
>(RpcModule, {
logger: false,
inject: [RpcOptionsProvider],
useFactory: (optionsProvider: RpcOptionsProvider) =>
optionsProvider.getOptions(),
});

await app.listen();
client = app.get('RPC_CLIENT', { strict: false });
});

it(`/POST`, done => {
let retData = 0;
client.send({ cmd: 'sum' }, [1, 2, 3, 4, 5]).subscribe({
next: val => (retData += val),
error: done,
complete: () => {
expect(retData).to.eq(15);
done();
},
});
});

afterEach(async () => {
await app.close();
});
});
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Type } from '@nestjs/common';
import { FactoryProvider, Type } from '@nestjs/common';
import { ConnectionOptions } from 'tls';
import { Transport } from '../enums/transport.enum';
import { ChannelOptions } from '../external/grpc-options.interface';
Expand Down Expand Up @@ -28,6 +28,16 @@ export type MicroserviceOptions =
| KafkaOptions
| CustomStrategy;

export type AsyncMicroserviceOptions = Omit<
FactoryProvider<MicroserviceOptions>,
'scope' | 'provide' | 'durable'
>;

export type AsyncOptions<T extends object> = Omit<
FactoryProvider<T>,
'scope' | 'provide' | 'durable'
>;

/**
* @publicApi
*/
Expand Down
28 changes: 21 additions & 7 deletions packages/microservices/nest-microservice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ import { GraphInspector } from '@nestjs/core/inspector/graph-inspector';
import { NestApplicationContext } from '@nestjs/core/nest-application-context';
import { Transport } from './enums/transport.enum';
import { CustomTransportStrategy } from './interfaces/custom-transport-strategy.interface';
import { MicroserviceOptions } from './interfaces/microservice-configuration.interface';
import {
AsyncMicroserviceOptions,
MicroserviceOptions,
} from './interfaces/microservice-configuration.interface';
import { MicroservicesModule } from './microservices-module';
import { Server } from './server/server';
import { ServerFactory } from './server/server-factory';
Expand All @@ -43,7 +46,8 @@ export class NestMicroservice

constructor(
container: NestContainer,
config: NestMicroserviceOptions & MicroserviceOptions = {},
config: NestMicroserviceOptions &
(MicroserviceOptions | AsyncMicroserviceOptions) = {},
private readonly graphInspector: GraphInspector,
private readonly applicationConfig: ApplicationConfig,
) {
Expand All @@ -60,12 +64,22 @@ export class NestMicroservice
this.selectContextModule();
}

public createServer(config: NestMicroserviceOptions & MicroserviceOptions) {
public createServer(
config: NestMicroserviceOptions &
(MicroserviceOptions | AsyncMicroserviceOptions),
) {
try {
this.microserviceConfig = {
transport: Transport.TCP,
...config,
} as any;
if ('useFactory' in config) {
const args = config.inject?.map(token =>
this.get(token, { strict: false }),
);
this.microserviceConfig = config.useFactory(...args);
} else {
this.microserviceConfig = {
transport: Transport.TCP,
...config,
} as any;
}
const { strategy } = config as any;
this.server = strategy
? strategy
Expand Down

0 comments on commit 7ed071d

Please sign in to comment.