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
refactor(#1640): support multiple packages (breaking changes) #1733
Conversation
d2ee6c9
to
f0f5c29
Compare
Pull Request Test Coverage Report for Build 1890
💛 - Coveralls |
Maybe I need to update interface GrpcOptions {
// ...
options: {
package?: string
packages?: string[]
}
} if one define a option like: export const grpcServerOptions: GrpcOptions = {
transport: Transport.GRPC,
options: {
url: `localhost:${config.payment.grpcPort}`,
package: 'payment',
packages: ['product', 'order'],
protoPath: join(__dirname, './proto/payment.proto'),
loader: {
includeDirs: [join(__dirname, 'proto')],
},
},
} then the actual used
|
f0f5c29
to
0663b74
Compare
The tests randomly failed in node v8 or node v11. I have no idea about it. |
One question towards the multi-package support, usually you start most of your interfaces with root namespace like: While compilation on rootless packaging probably may fail for some of the platforms supported by protobuf. Did you test that kind of a pattern for example on Python, Java and Go generation with GRPC enabled, and did it work and compile correctly? |
@anton-alation I just checked with my workmate, he said multi-package is fully supported in go gRPC. Not sure about other languages, I will figure it out if I have time. |
@anton-alation I agree with you that in most cases, we need only a root package for a gRPC service, but as client side, multi-package is needed. for example, if a Nest http server is an interface for several different gRPC microservices, and there're multiple packages served by those gRPC endpoints. We have to load more than one package which cannot be covered by current code base. |
By description you provided I can assume something is not right with the code examples above then:
Code example saying you loading all packages from the same file, while you describing multiple roots to be loaded. My assumption is that you want to have something like that: const grpcProductServerOptions: GrpcOptions = {
transport: Transport.GRPC,
options: {
url: 'localhost:5577',
package: "product",
protoPath: join(__dirname, './proto/product_service.proto'),
},
}
const grpcOrdersServerOptions: GrpcOptions = {
transport: Transport.GRPC,
options: {
url: 'localhost:5578',
package: "orders",
protoPath: join(__dirname, './proto/order_service.proto'),
},
}
/*
And controllers like
*/
@Controller()
export class ProductService {
}
@Controller()
export class OrderService {
} And then join those under the Nest HTTP Client proxy like: @Client({
transport: Transport.GRPC,
options: {
package: "product",
protoPath: join(__dirname, './proto/product_service.proto'),
},
})
clientProducts: ClientGrpc;
@Client({
transport: Transport.GRPC,
options: {
package: "orders",
protoPath: join(__dirname, './proto/order_service.proto'),
},
})
clientOrders: ClientGrpc;
onModuleInit() {
this.productService = this.clientProducts.getService<ProductService>('ProductService');
this.orderService = this.clientOrders.getService<OrderService>('OrderService');
} (c) https://docs.nestjs.com/microservices/grpc And that may work without additional adjustments of the codebase. But please let me know if that would not be a reasonable or workable solution. |
The Client part looks fairly good to me. 👍 const grpcProductServerOptions: GrpcOptions = {
transport: Transport.GRPC,
options: {
url: 'localhost:5577',
package: {
product: join(__dirname, './proto/product_service.proto'),
order: join(__dirname, './proto/order_service.proto'),
},
},
} Certainly, it's a better-to-have feature, and current solution provided by you, is okay to me. |
"package" is an grpc namespace. Namespace mutation inside the GrpcOptions in not well. May be it is sollution #1774 ? |
@aaskandrew Not exactly, but thanks for informing me this. |
This is not work for client |
hi, @AlexDaSoul . For client side, I accepted @anton-alation 's advise, so don't worry about it. I will revert those changes on client when I have time. |
PR #1774 is about ability to load more then one proto file. 'grpc' package allows this functionality. But this PR about load multiple namespaces in the nest GrpcClient. That can lead to conflicts in grpc services names with multi level namespaces. More over, problem of this PR resolves with multi level namespaces. file: order.proto file: product.proto file: some myGrpcConfig.ts: Problem is that construction @GrpcMethod('order.OrderService') is working but @client(myGrpcConfig) private readonly client: ClientGrpc; onModuleInit() { This problem for feature PR. |
It's really not obvious to figure out the problem from the message where the code isn't formatted into the blocks. |
sorry this.client.service('product.ProductService'); <== this is a current problem for me, it is not working It works only so: In the GrpcConfig object: In the code: |
My current production grpc config code. I prefer to remove
|
About code formatting: please use 3 backticks ` for format your code injections like that -> About client malfunction: so you saying |
|
I feel that it's just about defining your .proto files in another way, for example, you can just have one proto-file as a root file for all of those:
syntax = "proto3";
import public "candles.proto";
import public "health-webtrade.proto";
import public "marketdata.proto";
import public "markets.proto";
import public "order-book.proto";
import public "orders.proto";
import public "trading.proto";
import public "version-webtrade.proto"; And have then: grpcService: <GrpcOptions>{
transport: Transport.GRPC,
options: {
url: env.GRPC_TRADE_SERVICE || '0.0.0.0:9016',
package: 'sdex.webtrade',
protoPath: "webtrade.proto",
loader: {
includeDirs: [getProtoPath('common'), getProtoPath('webtrade')]
}
}
} And that (maybe some adjustments need) would resolve all of the files and services |
no, so:
and now 'grpc-web' is not working on the frontend :( |
Keep different services in the different files more more better for maintenance. Health and Version services I need insert into every nest microservice. |
Sure let me look on Config files are enough, still seems like problem resolution went too far away into the direction of having some very customized approach rather going through a simplified one. Please sync if you would be having any problems loading your files with a simplified approach. If you'll be trying that one of course. |
This is not a simplified approach, but the only one. When for use only 2 proto need adds 3th proto |
You can't use If you want to discuss more on this: please form an abstracted version of few of your files and I will be trying to help you with correct protobuf approach on the shared messages between namespaces. However if you thinking that you want to stay on the dynmaic codegen (which is doing some things out of common |
It works, and it was first version. Keep multiply proto files preferable for me. |
Protobuf files are all about business logic. Is there any reason that we would import a proto file from others' npm packages? |
For example when multiple owners of the packages and packages locations in different repositories |
This is the longest discussion in Nest PRs so far. Love it :)
The thing is that gRPC is a "language-agnostic" thing and thus we should try to stay as close as possible to other implementations. |
Sure. So need to have the alternative to choose |
Are we still in a canvas of microservices? :) It seems you trying to describe a macro-service with a lot of logic residing inside of one executor. For that one to succeed you certainly need also to define all of your parts to be well scalable within all of the interfaces you introducing, and that probably a bit tougher architectural conception to go with, rather than tiny-to-small logic segregation which allows components to stay maintainable at a reasonable point. Architectural discussions do carry even more controversy than interface discussions, so hopefully we'll not get into that messy swamp :)
Same thing here. Remember what are you trying to do here within this framework: reasonable microservices which easy to maintain, deploy and evolve. You can have all of the parts acting on the different ports independently and that may save your project in the future when you hit the traffic and will be in the situation of horizontal scaling. What you calling a bug now, may turn into a feature which would help resolve that situation in future. P.S. I need to repeat that I am not saying that not allowing to load multiple proto-files should stay like that, but certainly solution which we have now supported more developer culture and accuracy on interfaces rather than a solution with more freedom. Balance is a hard thing to achieve, and certainly, there should be a proposal which covers rest of the cases with most accuracy on interfaces in mind. |
It's very hard to have good unified interfaces for us all to work with, and it's even harder to make every platform to follow some new good ones. The reason that we'll here is that we all liked conception of Proto + GRPC and that is a success of one of the thousands of iterations of network interfaces through the last 30 years of software engineering controversy. |
protobufjs documentation: protoc documentation: Why they don't require to create '"barrel" file? Is it less "developer culture and accuracy on interfaces"? About standards. |
https://developers.google.com/protocol-buffers/docs/proto#packages |
Totally! It certainly will parse Caveat: Nest here trying to help you to automate bootstrapping of the You certainly need to separate two things from each other: I probably will be repeating myself but we need to take into account that The point here is that you should really provide the only service.proto files for the GRPC loader, not the rest of the files, and compiler will do the rest of the job, but do you actually need to know such little things while you just can have very valid root file. Sad thing that Protoc cannot really load dependency trees, and I can name it as a flaw for the tool, while I hope we shouldn't get into the discussion of why package roots should be the same for the library, company, product etc. logic. |
And it's supported, but obviously, rootless Nest GRPC for empty root will be just straight definitions of Service methods without any prefixes. |
Sounds very reasonable, but why that restriction? I think better to drop exception for this case. Cause "barrel" is not protects from it. a.proto b.proto barrel.proto But all of I wanted is to load from different files the same namespace without "barrel".
I am fully agree with it. In addition I can say that usually microservices sits under the proxy with routing (envoy) and common namespace actually needed. |
And let me add again: I am totally for support of loading all related service files into Also please take into account that |
Yes, "use ../ and ./" prohibited by google proto docs
I think that programmer with ability to understand namespaces must know that hi is do. |
Hmm... It is true for server, but what about client? :) this PR was stared from breaking nest binding rules.
|
We cannot expect that, but we can expect deep frustration when some things would not work according to expectations. So single
Clients are more flexible on the selection of services they want to connect to. One expectation is that |
But I am discussing exactly nest. Nest
With all due respect, mentoring is not the best way. In the summary, I don't want to have 'barrel' file. It isn't my paradigm. But if no way for it mean so be it. Respectfully, I finish this discussion. |
I am very sorry that we could not come to an understanding. We may have to use patches or forks of the microservice package to get the features we need. |
You can just point to single
I think we need to just allow multiple file-load and include a bunch of tests for the situations of:
As well if you loading multiple files then you need to understand how you'll be dealing with the situation of load-dir (which is usually serving as a root for namespace), and relative file-paths per each file. |
Returning to the discussion, one more use case. I have pool of grpc nest's microservices and 'envoy' proxy in front of them. Each upstream configured with 'grpc_health_check' that has only two parameters: Envoy ask about health the same port as main microcervice port, but with standard for grpc health URL 'grpc.health.v1'. So I can't to distribute packages on different ports and really need in different packages on the same port: ['appgrpcroot', 'grpc'] Envoy health_check GRPC health proto |
Add 1 scenario to rootless namespace practice: Our protobuf's root namespace is actually The standard So we might need to have 2 roots: Thanks in advance! |
Found the workaround for now: The An example: https://github.com/Jeff-Tian/grpc-health/blob/6715ff175b0882a467cf41e6f7b9fca3a5bc7f95/src/health/grpc-client.options.ts#L23 where the The I created a pacakge: grpc-health that applied the above logic and improved the hero sample app to show it works: https://github.com/Jeff-Tian/nestjs-hero-grpc-sample-with-health-check, the main change to the original sample is here: Jeff-Tian/nestjs-hero-grpc-sample-with-health-check@b76249c |
Partially added as part of this PR #3418 |
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs. |
PR Checklist
Please check if your PR fulfills the following requirements:
PR Type
What kind of change does this PR introduce?
What is the current behavior?
Issue Number: #1640
What is the new behavior?
Does this PR introduce a breaking change?
Other information