Refactor gRPC adapter to use connection pool and improve error handling in product retrieval

This commit is contained in:
2025-05-27 17:50:20 +03:00
parent b083cccc09
commit b48421e653
8 changed files with 44 additions and 40 deletions

View File

@@ -2,11 +2,11 @@ package marketplace
import (
"context"
"github.com/jackc/pgx/v5"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
pb "sipro-mps/api/generated/v1/marketplace"
"sipro-mps/internal/marketplace/db"
)
// AdapterGRPC implements the gRPC server for the Marketplace service.
@@ -20,11 +20,11 @@ func NewAdapterGRPC(repo Repository) *AdapterGRPC {
repo: repo,
}
}
func RegisterAdapterGRPC(server *grpc.Server) (*Repository, error) {
conn, err := pgx.Connect(context.Background(), "postgresql://postgres:GjitkeYf%5Beq@/sipro?host=/run/postgresql")
if err != nil {
return nil, err
}
func RegisterAdapterGRPC(server *grpc.Server, conn db.DBTX) (*Repository, error) {
//conn, err := pgx.Connect(context.Background(), "postgresql://postgres:GjitkeYf%5Beq@/sipro?host=/run/postgresql")
//if err != nil {
// return nil, err
//}
repo := NewDBRepository(conn)
adapter := NewAdapterGRPC(repo)
pb.RegisterMarketplaceServiceServer(server, adapter)

View File

@@ -2,15 +2,14 @@ package marketplace
import (
"context"
"github.com/jackc/pgx/v5"
"sipro-mps/internal/marketplace/db"
)
type dbRepository struct {
conn *pgx.Conn
conn db.DBTX
}
func NewDBRepository(conn *pgx.Conn) Repository {
func NewDBRepository(conn db.DBTX) Repository {
return &dbRepository{conn: conn}
}

View File

@@ -1,6 +1,7 @@
package products
import (
"fmt"
"github.com/samber/lo"
"google.golang.org/grpc"
pb "sipro-mps/api/generated/v1/ozon/products"
@@ -26,20 +27,23 @@ func RegisterAdapterGRPC(server *grpc.Server, marketplaceRepo marketplace.Reposi
pb.RegisterProductsServiceServer(server, adapter)
return &apiRepo, nil
}
func (g *AdapterGRPC) GetListOfProducts(req *pb.GetListOfProductsRequest, stream pb.ProductsService_GetListOfProductsServer) error {
ctx := stream.Context()
fmt.Printf("GetListOfProducts called with req: %+v\n", req.MarketplaceId)
converter := generated.ConverterImpl{}
resultChan := make(chan []OzonProduct)
errChan := make(chan error)
g.repo.StreamAllProducts(ctx, 262, resultChan, errChan)
go g.repo.StreamAllProducts(ctx, int(req.MarketplaceId), resultChan, errChan) // Запускаем в горутине
for {
select {
case <-ctx.Done():
return ctx.Err() // Handle context cancellation
fmt.Println("GetListOfProducts: context cancelled or deadline exceeded:", ctx.Err())
return ctx.Err()
case products, ok := <-resultChan:
if !ok {
return nil
return nil // Завершаем, только если результат закрыт
}
protoProducts := lo.Map(products, func(product OzonProduct, _ int) *pb.Product {
return converter.ToProto(&product)
@@ -48,13 +52,12 @@ func (g *AdapterGRPC) GetListOfProducts(req *pb.GetListOfProductsRequest, stream
Products: protoProducts,
}
if err := stream.Send(resp); err != nil {
return err // Error sending response
fmt.Println("GetListOfProducts: error sending response:", err)
return err
}
case err, ok := <-errChan:
if !ok {
return nil // Exit loop when errChan is closed
}
if err != nil {
if ok && err != nil {
fmt.Println("GetListOfProducts: error received from channel:", err)
return err
}
}

View File

@@ -31,8 +31,8 @@ func fetchProductIds(ctx context.Context, client *api.Client, resultChan chan<-
})
if err != nil {
// dev
panic(err)
//errChan <- fmt.Errorf("fetching product IDs: %w", err)
//panic(err)
errChan <- fmt.Errorf("fetching product IDs: %w", err)
return
}
@@ -65,8 +65,8 @@ func fetchProducts(ctx context.Context, client *api.Client, productIdsChan <-cha
})
if err != nil {
// dev
panic(err)
//errChan <- fmt.Errorf("fetching products: %w", err)
//panic(err)
errChan <- fmt.Errorf("fetching products: %w", err)
return
}
items := resp.Items

View File

@@ -43,7 +43,6 @@ type RateLimitTransport struct {
}
func (t *RateLimitTransport) RoundTrip(req *http.Request) (*http.Response, error) {
fmt.Println(time.Now().Format("2006-01-02 15:04:05"))
ctx := req.Context()
clientId := req.Header.Get("Client-Id")
now := time.Now().UnixNano()
@@ -57,6 +56,7 @@ func (t *RateLimitTransport) RoundTrip(req *http.Request) (*http.Response, error
return nil, fmt.Errorf("failed to execute rate limit script: %w", err)
}
if waitTime > 0 {
fmt.Printf("Rate limit exceeded for client %s, waiting for %d nanoseconds\n", clientId, waitTime)
time.Sleep(time.Duration(waitTime))
}
return t.RoundTripper.RoundTrip(req)