-
Notifications
You must be signed in to change notification settings - Fork 249
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
docs: update the multi-service doc (#1004)
- Loading branch information
1 parent
7ef5fa5
commit 4a284b7
Showing
1 changed file
with
102 additions
and
46 deletions.
There are no files selected for viewing
148 changes: 102 additions & 46 deletions
148
content/en/docs/kitex/Tutorials/advanced-feature/multi_service.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,90 +1,146 @@ | ||
--- | ||
title: "Multiple Services" | ||
date: 2023-11-09 | ||
date: 2024-03-05 | ||
weight: 10 | ||
keywords: ["Kitex", "Multi Services", "gRPC"] | ||
keywords: ["Kitex", "Multi Services", "gRPC", "thrift", "protobuf"] | ||
description: Kitex supports multiple service registration on a server. | ||
--- | ||
|
||
Note: currently, the feature is only available for **gRPC** transport protocol. | ||
Currently, the feature is available for: | ||
- gRPC transport protocol | ||
- Kitex thrift and protobuf (non-streaming) | ||
|
||
## Usage | ||
|
||
### gRPC service definition | ||
For instance, suppose you have two proto files as follows, each containing one service. | ||
By running the kitex command, you can automatically generate the code. | ||
|
||
```protobuf | ||
// File1:servicea.proto | ||
syntax = "proto3"; | ||
### Preparation | ||
Please generate code for each service using Kitex command tool. For more details, please refer to [Code Generation Tool](https://www.cloudwego.io/docs/kitex/tutorials/code-gen/code_generation/). | ||
|
||
The results of code generation will be as follows: | ||
```text | ||
kitex_gen | ||
|_ api | ||
|_ servicea | ||
|_ client.go | ||
|_ invoker.go | ||
|_ server.go | ||
|_ servicea.go | ||
|_ serviceb | ||
|_ client.go | ||
|_ invoker.go | ||
|_ server.go | ||
|_ serviceb.go | ||
|_ ... | ||
``` | ||
|
||
option go_package = "myservice"; | ||
You will see `RegisterService` func in each service's `server.go`. | ||
```golang | ||
func RegisterService(svr server.Server, handler XXX, opts ...server.RegisterOption) error { | ||
if err := svr.RegisterService(serviceInfo(), handler, opts...); err != nil { | ||
return err | ||
} | ||
return nil | ||
} | ||
``` | ||
|
||
package myservice; | ||
### Create a server and register your services on the server | ||
Registering services on a server is a straightforward process. | ||
|
||
service ServiceA { | ||
rpc EchoA (stream RequestA) returns (stream ReplyA) {} | ||
} | ||
First, create a server. Then, by calling the `RegisterService` function in your generated code, a service can be registered. | ||
|
||
message RequestA { | ||
... | ||
} | ||
Multiple services can be called on the same server, registering as many services as needed. | ||
|
||
message ReplyA { | ||
... | ||
} | ||
```golang | ||
package main | ||
|
||
import ( | ||
"github.com/cloudwego/kitex/pkg/server" | ||
|
||
// File2:serviceb.proto | ||
syntax = "proto3"; | ||
servicea "your_servicea_kitex_gen_path" | ||
serviceb "your_serviceb_kitex_gen_path" | ||
) | ||
|
||
option go_package = "myservice"; | ||
func main() { | ||
// create a server by calling server.NewServer | ||
svr := server.NewServer(your_server_option) | ||
// register multi-service on a server | ||
err := servicea.RegisterService(svr, new(ServiceAImpl)) | ||
err = serviceb.RegisterService(svr, new(ServiceBImpl)) | ||
|
||
package myservice; | ||
err = svr.Run() | ||
|
||
service ServiceB { | ||
rpc EchoB (stream RequestB) returns (stream ReplyB) {} | ||
if err != nil { | ||
logs.Error("%s", err.Error()) | ||
} | ||
logs.Stop() | ||
} | ||
``` | ||
|
||
### Fallback service | ||
Suppose there is the same named method between services. | ||
|
||
```thrift | ||
// demo.thrift | ||
namespace go api | ||
message RequestB { | ||
... | ||
struct Request { | ||
1: string message | ||
} | ||
message ReplyB { | ||
... | ||
struct Response { | ||
1: string message | ||
} | ||
``` | ||
### Register multi-service on a server | ||
service ServiceA { | ||
Response sameNamedMethod(1: Request req) | ||
} | ||
Registering services on a server is a straightforward process. | ||
service ServiceB { | ||
Response sameNamedMethod(1: Request req) | ||
} | ||
``` | ||
|
||
First, create a server. Then, by calling the `RegisterService` function on that server, a service can be registered. | ||
In this case, **please note that you need to specify one service as a fallback service.** | ||
|
||
Multiple services can be called on the same server, registering as many services as needed. | ||
Fallback service is used to maintain compatibility when the client is using an old Kitex version (< v0.9.0) | ||
or when `TTHeader` is not being used for transport protocol, | ||
or the client does not set an optional meta handler `transmeta.ClientTTHeaderHandler()`. | ||
|
||
```golang | ||
package main | ||
If you don't specify any fallback service or if you specify multiple fallback services, an error will be returned on server startup. | ||
|
||
import ( | ||
"github.com/cloudwego/kitex/pkg/server" | ||
Note that you can specify only one service as a fallback service. | ||
|
||
servicea "your_servicea_kitex_gen_path" | ||
serviceb "your_serviceb_kitex_gen_path" | ||
) | ||
`RegisterService()` in the generated code (`server.go`) has an optional argument:`server.RegisterOption`. | ||
If `server.WithFallbackService` option is passed, the service will be registered as a fallback service. | ||
|
||
```golang | ||
func main() { | ||
// create a server by calling server.NewServer | ||
svr := server.NewServer(your_server_option) | ||
// register multi-service on a server | ||
err := svr.RegisterService(servicea.NewServiceInfo(), new(ServiceAImpl)) | ||
err := svr.RegisterService(serviceb.NewServiceInfo(), new(ServiceBImpl)) | ||
// servicea will be a fallback service | ||
servicea.RegisterService(svr, new(ServiceAImpl), server.WithFallbackService()) | ||
serviceb.RegisterService(svr, new(ServiceBImpl)) | ||
|
||
err := svr.Run() | ||
|
||
if err != nil { | ||
logs.Error("%s", err.Error()) | ||
} | ||
logs.Stop() | ||
} | ||
``` | ||
|
||
Another way to avoid an error on server startup without specifying a fallback service is to use the option `server.WithRefuseTrafficWithoutServiceName`. | ||
|
||
With this option, no error is returned when starting up the server even when you don't specify a fallback service for your method with conflicting names. | ||
|
||
But when using this option, the following must be noted: | ||
|
||
When `server.WithRefuseTrafficWithoutServiceName` option is enabled, an error will occur with a message "no service name while the server has WithRefuseTrafficWithoutServiceName option enabled" | ||
if the server receives requests in the following cases: | ||
- Client uses the older Kitex version (< v0.9.0), which does not support multi-service feature | ||
- The transport protocol of a request is not TTHeader (Kitex pb's transport protocol enables TTHeader by default) | ||
|
||
### Combine Service | ||
Please note that if you register combine service (codes are generated using -combine-service flag), | ||
**only one service (= combine service) can be registered on a server**. | ||
Otherwise, you'll receive an error message saying "only one service can be registered when registering combined service". |