Add Wildberries product fetching and rate limiting functionality
This commit is contained in:
		
							
								
								
									
										65
									
								
								internal/tasks/wb/wb.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								internal/tasks/wb/wb.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,65 @@
 | 
			
		||||
package wb
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"github.com/hibiken/asynq"
 | 
			
		||||
	"github.com/jackc/pgx/v5/pgxpool"
 | 
			
		||||
	"github.com/samber/lo"
 | 
			
		||||
	pb "sipro-mps/api/generated/v1/wb/products"
 | 
			
		||||
	mp_repo "sipro-mps/internal/marketplace"
 | 
			
		||||
	"sipro-mps/internal/redis"
 | 
			
		||||
	"sipro-mps/internal/tasks/types"
 | 
			
		||||
	wb_products_repo "sipro-mps/internal/wb/products"
 | 
			
		||||
	conv "sipro-mps/internal/wb/products/mapping/generated"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type FetchProductsProcessor struct {
 | 
			
		||||
	Dbpool *pgxpool.Pool
 | 
			
		||||
	wbRepo wb_products_repo.Repository
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *FetchProductsProcessor) ProcessTask(ctx context.Context, task *asynq.Task) error {
 | 
			
		||||
	var payload types.FetchProductsTask
 | 
			
		||||
	if err := json.Unmarshal(task.Payload(), &payload); err != nil {
 | 
			
		||||
		return asynq.SkipRetry
 | 
			
		||||
	}
 | 
			
		||||
	marketplaceRepo := mp_repo.NewDBRepository(p.Dbpool)
 | 
			
		||||
	repo := wb_products_repo.NewAPIRepository(marketplaceRepo)
 | 
			
		||||
	_, sellerId, err := repo.ParseMarketplace(ctx, payload.MarketplaceId)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("failed to parse marketplace %d: %w", payload.MarketplaceId, err)
 | 
			
		||||
	}
 | 
			
		||||
	locker := *redis.Locker
 | 
			
		||||
	_, cancel, err := locker.TryWithContext(ctx, fmt.Sprintf("wb:products:marketplace:%s:lock", sellerId))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Printf("Failed to acquire lock for marketplace %s: %v\n", sellerId, err)
 | 
			
		||||
		return asynq.SkipRetry
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
	fmt.Println("Working on marketplace", payload.MarketplaceId, "with seller ID", sellerId)
 | 
			
		||||
 | 
			
		||||
	defer cancel()
 | 
			
		||||
 | 
			
		||||
	redisKey := fmt.Sprintf("wb:products:%s", sellerId)
 | 
			
		||||
	productsRaw, err := repo.GetAllProducts(ctx, payload.MarketplaceId)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("failed to fetch products for marketplace %d: %w", payload.MarketplaceId, err)
 | 
			
		||||
	}
 | 
			
		||||
	converter := conv.ConverterImpl{}
 | 
			
		||||
	products := lo.Map(productsRaw, func(item wb_products_repo.WbProduct, _ int) *pb.Product {
 | 
			
		||||
		return converter.ToProto(&item)
 | 
			
		||||
	})
 | 
			
		||||
	redisClient := *redis.Client
 | 
			
		||||
	productsJson, err := json.Marshal(products)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("failed to marshal products: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
	err = redisClient.Do(ctx, redisClient.B().Set().Key(redisKey).Value(string(productsJson)).Build()).Error()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user