From 5ac3637deee4cc73d5c46e0624db2fb831034b93 Mon Sep 17 00:00:00 2001 From: Sebastian Schmid Date: Mon, 18 Oct 2021 23:37:33 +0200 Subject: [PATCH 1/4] The GrpcOptions attribute "channelOptions" was not used anymore (never read in the code). Therefore, declaring those ChannelOptions had no effect anymore and there was no way to configure specific gRPC settings & limits. Also extended ChannelOptions with grpc-node.max_session_memory which is required when sending big messages (see https://github.com/grpc/grpc-node/pull/1666). Ensured backward compatibility by including size limits like grpc.max_send_message_length to the ChannelOptions --- .../external/grpc-options.interface.ts | 6 ++++ packages/microservices/server/server-grpc.ts | 31 +++++++------------ 2 files changed, 17 insertions(+), 20 deletions(-) diff --git a/packages/microservices/external/grpc-options.interface.ts b/packages/microservices/external/grpc-options.interface.ts index 53484a281c0..a500fa6e947 100644 --- a/packages/microservices/external/grpc-options.interface.ts +++ b/packages/microservices/external/grpc-options.interface.ts @@ -1,8 +1,13 @@ +import {GRPC_DEFAULT_MAX_SEND_MESSAGE_LENGTH} from "../constants"; + /** * An interface that contains options used when initializing a Channel instance. * This listing is incomplete. Full reference: https://grpc.github.io/grpc/core/group__grpc__arg__keys.html */ export interface ChannelOptions { + 'grpc.max_send_message_length'?: number; + 'grpc.max_receive_message_length'?: number; + 'grpc.max_metadata_size'?: number; 'grpc.ssl_target_name_override'?: string; 'grpc.primary_user_agent'?: string; 'grpc.secondary_user_agent'?: string; @@ -12,5 +17,6 @@ export interface ChannelOptions { 'grpc.initial_reconnect_backoff_ms'?: number; 'grpc.max_reconnect_backoff_ms'?: number; 'grpc.use_local_subchannel_pool'?: number; + 'grpc-node.max_session_memory'?: number; [key: string]: string | number | undefined; } diff --git a/packages/microservices/server/server-grpc.ts b/packages/microservices/server/server-grpc.ts index fc5a0a92fad..6d02d400fc9 100644 --- a/packages/microservices/server/server-grpc.ts +++ b/packages/microservices/server/server-grpc.ts @@ -19,6 +19,7 @@ import { InvalidProtoDefinitionException } from '../errors/invalid-proto-definit import { CustomTransportStrategy, MessageHandler } from '../interfaces'; import { GrpcOptions } from '../interfaces/microservice-configuration.interface'; import { Server } from './server'; +import {ChannelOptions} from "../external/grpc-options.interface"; let grpcPackage: any = {}; let grpcProtoLoaderPackage: any = {}; @@ -333,27 +334,17 @@ export class ServerGrpc extends Server implements CustomTransportStrategy { } public async createClient(): Promise { - const grpcOptions = { - 'grpc.max_send_message_length': this.getOptionsProp( - this.options, - 'maxSendMessageLength', - GRPC_DEFAULT_MAX_SEND_MESSAGE_LENGTH, - ), - 'grpc.max_receive_message_length': this.getOptionsProp( - this.options, - 'maxReceiveMessageLength', - GRPC_DEFAULT_MAX_RECEIVE_MESSAGE_LENGTH, - ), - }; - const maxMetadataSize = this.getOptionsProp( - this.options, - 'maxMetadataSize', - -1, - ); - if (maxMetadataSize > 0) { - grpcOptions['grpc.max_metadata_size'] = maxMetadataSize; + const channelOptions: ChannelOptions = this.options && this.options.channelOptions ? this.options.channelOptions : {}; + if (this.options && this.options.maxSendMessageLength) { + channelOptions["grpc.max_send_message_length"] = this.options.maxSendMessageLength; + } + if (this.options && this.options.maxReceiveMessageLength) { + channelOptions["grpc.max_receive_message_length"] = this.options.maxReceiveMessageLength; + } + if (this.options && this.options.maxMetadataSize) { + channelOptions["grpc.max_metadata_size"] = this.options.maxMetadataSize; } - const server = new grpcPackage.Server(grpcOptions); + const server = new grpcPackage.Server(channelOptions); const credentials = this.getOptionsProp(this.options, 'credentials'); await new Promise((resolve, reject) => { From e88e310731ae226b90ac21c5e4dd425dc9aac2d1 Mon Sep 17 00:00:00 2001 From: Sebastian Schmid Date: Mon, 18 Oct 2021 23:48:00 +0200 Subject: [PATCH 2/4] cleanup --- packages/microservices/external/grpc-options.interface.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/microservices/external/grpc-options.interface.ts b/packages/microservices/external/grpc-options.interface.ts index a500fa6e947..f00fb4cb799 100644 --- a/packages/microservices/external/grpc-options.interface.ts +++ b/packages/microservices/external/grpc-options.interface.ts @@ -1,5 +1,3 @@ -import {GRPC_DEFAULT_MAX_SEND_MESSAGE_LENGTH} from "../constants"; - /** * An interface that contains options used when initializing a Channel instance. * This listing is incomplete. Full reference: https://grpc.github.io/grpc/core/group__grpc__arg__keys.html From 25dbb330cd61d921c3795ceb2effb57ccc3baee1 Mon Sep 17 00:00:00 2001 From: Sebastian Schmid Date: Tue, 19 Oct 2021 10:10:45 +0200 Subject: [PATCH 3/4] Alligned gRPC ChannelOptions code in server and client. Removed GRPC_DEFAULT_MAX_RECEIVE_MESSAGE_LENGTH and GRPC_DEFAULT_MAX_SEND_MESSAGE_LENGTH constants. This default values are already the same in the underlying gRPC library. If the gRPC team decides to change that values in the future, nestjs should adopt the new values automatically. --- packages/microservices/client/client-grpc.ts | 36 ++++++-------------- packages/microservices/constants.ts | 2 -- packages/microservices/server/server-grpc.ts | 2 -- 3 files changed, 11 insertions(+), 29 deletions(-) diff --git a/packages/microservices/client/client-grpc.ts b/packages/microservices/client/client-grpc.ts index 357bd198225..38c2bcc00bf 100644 --- a/packages/microservices/client/client-grpc.ts +++ b/packages/microservices/client/client-grpc.ts @@ -3,8 +3,6 @@ import { loadPackage } from '@nestjs/common/utils/load-package.util'; import { isFunction, isObject } from '@nestjs/common/utils/shared.utils'; import { Observable, Subscription } from 'rxjs'; import { - GRPC_DEFAULT_MAX_RECEIVE_MESSAGE_LENGTH, - GRPC_DEFAULT_MAX_SEND_MESSAGE_LENGTH, GRPC_DEFAULT_PROTO_LOADER, GRPC_DEFAULT_URL, } from '../constants'; @@ -14,6 +12,7 @@ import { InvalidProtoDefinitionException } from '../errors/invalid-proto-definit import { ClientGrpc, GrpcOptions } from '../interfaces'; import { ClientProxy } from './client-proxy'; import { GRPC_CANCELLED } from './constants'; +import {ChannelOptions} from "../external/grpc-options.interface"; let grpcPackage: any = {}; let grpcProtoLoaderPackage: any = {}; @@ -65,33 +64,20 @@ export class ClientGrpcProxy extends ClientProxy implements ClientGrpc { throw new InvalidGrpcServiceException(); } - const maxSendMessageLengthKey = 'grpc.max_send_message_length'; - const maxReceiveMessageLengthKey = 'grpc.max_receive_message_length'; - const maxMessageLengthOptions = { - [maxSendMessageLengthKey]: this.getOptionsProp( - this.options, - 'maxSendMessageLength', - GRPC_DEFAULT_MAX_SEND_MESSAGE_LENGTH, - ), - [maxReceiveMessageLengthKey]: this.getOptionsProp( - this.options, - 'maxReceiveMessageLength', - GRPC_DEFAULT_MAX_RECEIVE_MESSAGE_LENGTH, - ), - }; - const maxMetadataSize = this.getOptionsProp( - this.options, - 'maxMetadataSize', - -1, - ); - if (maxMetadataSize > 0) { - maxMessageLengthOptions['grpc.max_metadata_size'] = maxMetadataSize; + const channelOptions: ChannelOptions = this.options && this.options.channelOptions ? this.options.channelOptions : {}; + if (this.options && this.options.maxSendMessageLength) { + channelOptions["grpc.max_send_message_length"] = this.options.maxSendMessageLength; + } + if (this.options && this.options.maxReceiveMessageLength) { + channelOptions["grpc.max_receive_message_length"] = this.options.maxReceiveMessageLength; + } + if (this.options && this.options.maxMetadataSize) { + channelOptions["grpc.max_metadata_size"] = this.options.maxMetadataSize; } const keepaliveOptions = this.getKeepaliveOptions(); const options: Record = { - ...(this.options.channelOptions || {}), - ...maxMessageLengthOptions, + ...channelOptions, ...keepaliveOptions, }; diff --git a/packages/microservices/constants.ts b/packages/microservices/constants.ts index 79c5ea54c07..7999319b4d4 100644 --- a/packages/microservices/constants.ts +++ b/packages/microservices/constants.ts @@ -39,8 +39,6 @@ export const GRPC_DEFAULT_PROTO_LOADER = '@grpc/proto-loader'; export const NO_MESSAGE_HANDLER = `There is no matching message handler defined in the remote service.`; export const NO_EVENT_HANDLER = `There is no matching event handler defined in the remote service.`; export const DISCONNECTED_RMQ_MESSAGE = `Disconnected from RMQ. Trying to reconnect.`; -export const GRPC_DEFAULT_MAX_RECEIVE_MESSAGE_LENGTH = 4 * 1024 * 1024; -export const GRPC_DEFAULT_MAX_SEND_MESSAGE_LENGTH = 4 * 1024 * 1024; export const KAFKA_DEFAULT_CLIENT = 'nestjs-consumer'; export const KAFKA_DEFAULT_GROUP = 'nestjs-group'; diff --git a/packages/microservices/server/server-grpc.ts b/packages/microservices/server/server-grpc.ts index 6d02d400fc9..7ef4e4e9412 100644 --- a/packages/microservices/server/server-grpc.ts +++ b/packages/microservices/server/server-grpc.ts @@ -7,8 +7,6 @@ import { EMPTY, fromEvent, lastValueFrom, Subject } from 'rxjs'; import { catchError, takeUntil } from 'rxjs/operators'; import { CANCEL_EVENT, - GRPC_DEFAULT_MAX_RECEIVE_MESSAGE_LENGTH, - GRPC_DEFAULT_MAX_SEND_MESSAGE_LENGTH, GRPC_DEFAULT_PROTO_LOADER, GRPC_DEFAULT_URL, } from '../constants'; From fdf11a51ae3d60719cd0f98da2b556a236e598eb Mon Sep 17 00:00:00 2001 From: Sebastian Schmid Date: Wed, 27 Oct 2021 13:57:15 +0200 Subject: [PATCH 4/4] fix(microservices): npm run format --- packages/microservices/client/client-grpc.ts | 20 ++++++++++--------- .../microservice-configuration.interface.ts | 4 +++- packages/microservices/server/server-grpc.ts | 15 +++++++++----- 3 files changed, 24 insertions(+), 15 deletions(-) diff --git a/packages/microservices/client/client-grpc.ts b/packages/microservices/client/client-grpc.ts index 38c2bcc00bf..3ddd9bf5f0a 100644 --- a/packages/microservices/client/client-grpc.ts +++ b/packages/microservices/client/client-grpc.ts @@ -2,17 +2,14 @@ import { Logger } from '@nestjs/common/services/logger.service'; import { loadPackage } from '@nestjs/common/utils/load-package.util'; import { isFunction, isObject } from '@nestjs/common/utils/shared.utils'; import { Observable, Subscription } from 'rxjs'; -import { - GRPC_DEFAULT_PROTO_LOADER, - GRPC_DEFAULT_URL, -} from '../constants'; +import { GRPC_DEFAULT_PROTO_LOADER, GRPC_DEFAULT_URL } from '../constants'; import { InvalidGrpcPackageException } from '../errors/invalid-grpc-package.exception'; import { InvalidGrpcServiceException } from '../errors/invalid-grpc-service.exception'; import { InvalidProtoDefinitionException } from '../errors/invalid-proto-definition.exception'; import { ClientGrpc, GrpcOptions } from '../interfaces'; import { ClientProxy } from './client-proxy'; import { GRPC_CANCELLED } from './constants'; -import {ChannelOptions} from "../external/grpc-options.interface"; +import { ChannelOptions } from '../external/grpc-options.interface'; let grpcPackage: any = {}; let grpcProtoLoaderPackage: any = {}; @@ -64,15 +61,20 @@ export class ClientGrpcProxy extends ClientProxy implements ClientGrpc { throw new InvalidGrpcServiceException(); } - const channelOptions: ChannelOptions = this.options && this.options.channelOptions ? this.options.channelOptions : {}; + const channelOptions: ChannelOptions = + this.options && this.options.channelOptions + ? this.options.channelOptions + : {}; if (this.options && this.options.maxSendMessageLength) { - channelOptions["grpc.max_send_message_length"] = this.options.maxSendMessageLength; + channelOptions['grpc.max_send_message_length'] = + this.options.maxSendMessageLength; } if (this.options && this.options.maxReceiveMessageLength) { - channelOptions["grpc.max_receive_message_length"] = this.options.maxReceiveMessageLength; + channelOptions['grpc.max_receive_message_length'] = + this.options.maxReceiveMessageLength; } if (this.options && this.options.maxMetadataSize) { - channelOptions["grpc.max_metadata_size"] = this.options.maxMetadataSize; + channelOptions['grpc.max_metadata_size'] = this.options.maxMetadataSize; } const keepaliveOptions = this.getKeepaliveOptions(); diff --git a/packages/microservices/interfaces/microservice-configuration.interface.ts b/packages/microservices/interfaces/microservice-configuration.interface.ts index defc13307e4..11a82765176 100644 --- a/packages/microservices/interfaces/microservice-configuration.interface.ts +++ b/packages/microservices/interfaces/microservice-configuration.interface.ts @@ -33,7 +33,9 @@ export interface CustomStrategy { export interface GrpcOptions { transport?: Transport.GRPC; options: { - interceptors?: Array<(options: any, nextCall: (options: any) => any) => any>; + interceptors?: Array< + (options: any, nextCall: (options: any) => any) => any + >; url?: string; maxSendMessageLength?: number; maxReceiveMessageLength?: number; diff --git a/packages/microservices/server/server-grpc.ts b/packages/microservices/server/server-grpc.ts index 7ef4e4e9412..b744c2e1bd8 100644 --- a/packages/microservices/server/server-grpc.ts +++ b/packages/microservices/server/server-grpc.ts @@ -17,7 +17,7 @@ import { InvalidProtoDefinitionException } from '../errors/invalid-proto-definit import { CustomTransportStrategy, MessageHandler } from '../interfaces'; import { GrpcOptions } from '../interfaces/microservice-configuration.interface'; import { Server } from './server'; -import {ChannelOptions} from "../external/grpc-options.interface"; +import { ChannelOptions } from '../external/grpc-options.interface'; let grpcPackage: any = {}; let grpcProtoLoaderPackage: any = {}; @@ -332,15 +332,20 @@ export class ServerGrpc extends Server implements CustomTransportStrategy { } public async createClient(): Promise { - const channelOptions: ChannelOptions = this.options && this.options.channelOptions ? this.options.channelOptions : {}; + const channelOptions: ChannelOptions = + this.options && this.options.channelOptions + ? this.options.channelOptions + : {}; if (this.options && this.options.maxSendMessageLength) { - channelOptions["grpc.max_send_message_length"] = this.options.maxSendMessageLength; + channelOptions['grpc.max_send_message_length'] = + this.options.maxSendMessageLength; } if (this.options && this.options.maxReceiveMessageLength) { - channelOptions["grpc.max_receive_message_length"] = this.options.maxReceiveMessageLength; + channelOptions['grpc.max_receive_message_length'] = + this.options.maxReceiveMessageLength; } if (this.options && this.options.maxMetadataSize) { - channelOptions["grpc.max_metadata_size"] = this.options.maxMetadataSize; + channelOptions['grpc.max_metadata_size'] = this.options.maxMetadataSize; } const server = new grpcPackage.Server(channelOptions); const credentials = this.getOptionsProp(this.options, 'credentials');