Как смоделировать клиентов Grpc внутри реализации сервера GRPC - PullRequest
0 голосов
/ 23 октября 2019

У меня есть сервер GRPC, который общается со многими другими серверами GRPC. Итак, мой сервер является клиентом для многих других серверов GRPC, я хотел бы протестировать реализацию своего сервера, но я застрял на том, как имитировать клиентов GRPC.

У меня есть метод с моего сервера GRPC, подобный этому:

func (s UserBackendServer) UpdateUser(ctx context.Context, req *api.UpdateUserRequest) (*api.User, error) {
    conn, err := grpc.DialContext(ctx, s.userSvcAddr,
        grpc.WithInsecure(),
        grpc.WithStatsHandler(&ocgrpc.ClientHandler{}))
    if err != nil {
        return nil, fmt.Errorf("could not connect shipping service: %+v", err)
    }
    defer conn.Close()

    user, err := api.NewUserServiceClient(conn).
        UpdateUser(ctx, &api.UpdateUserRequest{
        User:                 nil,
        UserId:               "",
    })
    return user, nil
}

В этом типе реализации я не могу издеваться над UserServiceClient, потому что создаю его внутри метода: (

Я думал о двух способах решения этой проблемы

  1. Имейте ссылку на клиента внутри UserBackendServer struct
type UserBackendServer struct {
    projectID string
    userSvcClient api.UserServiceClient
}

func (s UserBackendServer) UpdateUser(ctx context.Context, req *api.UpdateUserRequest) (*api.User, error) {
    conn, err := grpc.DialContext(ctx, s.userSvcAddr,
        grpc.WithInsecure(),
        grpc.WithStatsHandler(&ocgrpc.ClientHandler{}))
    if err != nil {
        return nil, fmt.Errorf("could not connect shipping service: %+v", err)
    }
    defer conn.Close()

    user, err := s.userSvcClient.UpdateUser(ctx, &api.UpdateUserRequest{
        User:                 nil,
        UserId:               "",
    })
    return user, nil
}

В этой реализации у меня есть побочный эффект от наличия постоянно активного соединения с клиентами (у меня как 10 клиентов ксвязаться с). Это нормально в производстве? Наличие всегда подключенных клиентов может привести к утечке памяти или слишком много параллельных соединений?

Использование методов, которые получают клиент в качестве аргумента
func (s UserBackendServer) UpdateUser(ctx context.Context, req *api.UpdateUserRequest) (*api.User, error) {
    conn, err := grpc.DialContext(ctx, s.userSvcAddr,
        grpc.WithInsecure(),
        grpc.WithStatsHandler(&ocgrpc.ClientHandler{}))
    if err != nil {
        return nil, fmt.Errorf("could not connect shipping service: %+v", err)
    }
    defer conn.Close()

    client := api.NewUserServiceClient(conn)
    updateUser(ctx, req.UserId, req.User, client)


    user, err := s.userSvcClient.UpdateUser(ctx, &api.UpdateUserRequest{
        User:                 nil,
        UserId:               "",
    })
    return user, nil
}

func updateUser(ctx context.Context, userId string, user *api.User, client api.UserServiceClient) (*api.User, error){
    userUpdated, err := client.UpdateUser(ctx, &api.UpdateUserRequest{
        User:                 nil,
        UserId:               "",
    })

    return userUpdated, err
}

Писать все эти маленькие функции немного громоздко, и я не могу выполнить модульный тест серверной функции.

Стратегия номер один, осуществима ли? У вас есть опыт работы с ограничениями или как повторить неудачные соединения, если соединения поддерживаются в структуре сервера

...