mirror of
https://github.com/3ybactuk/marketplace-go-service-project.git
synced 2025-10-30 14:03:45 +03:00
[hw-6] add notifier service, kafka
This commit is contained in:
@@ -35,17 +35,23 @@ type txManager interface {
|
||||
ReadWithRepeatableRead(ctx context.Context, fn func(ctx context.Context) error) (err error)
|
||||
}
|
||||
|
||||
type LomsService struct {
|
||||
orders OrderRepository
|
||||
stocks StockRepository
|
||||
txManager txManager
|
||||
type StatusProducer interface {
|
||||
Send(ctx context.Context, id entity.ID, status string) error
|
||||
}
|
||||
|
||||
func NewLomsService(orderRepo OrderRepository, stockRepo StockRepository, txManager txManager) *LomsService {
|
||||
type LomsService struct {
|
||||
orders OrderRepository
|
||||
stocks StockRepository
|
||||
txManager txManager
|
||||
statusProducer StatusProducer
|
||||
}
|
||||
|
||||
func NewLomsService(orderRepo OrderRepository, stockRepo StockRepository, txManager txManager, statusProducer StatusProducer) *LomsService {
|
||||
return &LomsService{
|
||||
orders: orderRepo,
|
||||
stocks: stockRepo,
|
||||
txManager: txManager,
|
||||
orders: orderRepo,
|
||||
stocks: stockRepo,
|
||||
txManager: txManager,
|
||||
statusProducer: statusProducer,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,17 +63,24 @@ func (s *LomsService) rollbackStocks(ctx context.Context, stocks []*entity.Stock
|
||||
}
|
||||
}
|
||||
|
||||
func (s *LomsService) OrderCreate(ctx context.Context, orderReq *pb.OrderCreateRequest) (entity.ID, error) {
|
||||
if orderReq == nil || orderReq.UserId <= 0 || len(orderReq.Items) == 0 {
|
||||
return 0, model.ErrInvalidInput
|
||||
// Wraps writing status to DB and status topic.
|
||||
// Should use this function for status updates.
|
||||
// Guarantees that status upd event will be sent only if DB write is successful.
|
||||
func (s *LomsService) setStatus(ctx context.Context, id entity.ID, status string) error {
|
||||
log.Trace().Msgf("running status update for %d with status %s", id, status)
|
||||
|
||||
if err := s.orders.OrderSetStatus(ctx, id, status); err != nil {
|
||||
return fmt.Errorf("orders.OrderSetStatus: %w", err)
|
||||
}
|
||||
|
||||
for _, item := range orderReq.Items {
|
||||
if item.Sku <= 0 || item.Count == 0 {
|
||||
return 0, model.ErrInvalidInput
|
||||
}
|
||||
if err := s.statusProducer.Send(ctx, id, status); err != nil {
|
||||
log.Error().Err(err).Msg("statusProducer.Send")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *LomsService) createInitial(ctx context.Context, orderReq *pb.OrderCreateRequest) (*entity.Order, error) {
|
||||
order := &entity.Order{
|
||||
OrderID: 0,
|
||||
Status: pb.OrderStatus_ORDER_STATUS_NEW.String(),
|
||||
@@ -86,44 +99,82 @@ func (s *LomsService) OrderCreate(ctx context.Context, orderReq *pb.OrderCreateR
|
||||
return int(a.ID - b.ID)
|
||||
})
|
||||
|
||||
var (
|
||||
orderID entity.ID
|
||||
resErr error
|
||||
)
|
||||
|
||||
err := s.txManager.WriteWithTransaction(ctx, func(txCtx context.Context) error {
|
||||
id, err := s.orders.OrderCreate(txCtx, order)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
order.OrderID = id
|
||||
orderID = id
|
||||
|
||||
order.OrderID = id
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return order, nil
|
||||
}
|
||||
|
||||
func (s *LomsService) OrderCreate(ctx context.Context, orderReq *pb.OrderCreateRequest) (entity.ID, error) {
|
||||
if orderReq == nil || orderReq.UserId <= 0 || len(orderReq.Items) == 0 {
|
||||
return 0, model.ErrInvalidInput
|
||||
}
|
||||
|
||||
for _, item := range orderReq.Items {
|
||||
if item.Sku <= 0 || item.Count == 0 {
|
||||
return 0, model.ErrInvalidInput
|
||||
}
|
||||
}
|
||||
|
||||
order, err := s.createInitial(ctx, orderReq)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if statErr := s.setStatus(ctx, order.OrderID, order.Status); statErr != nil {
|
||||
return 0, statErr
|
||||
}
|
||||
|
||||
var resErr error
|
||||
|
||||
err = s.txManager.WriteWithTransaction(ctx, func(txCtx context.Context) error {
|
||||
committed := make([]*entity.Stock, 0, len(order.Items))
|
||||
for _, it := range order.Items {
|
||||
st := &entity.Stock{Item: it, Reserved: it.Count}
|
||||
if err := s.stocks.StockReserve(txCtx, st); err != nil {
|
||||
if resErr = s.stocks.StockReserve(txCtx, st); resErr != nil {
|
||||
s.rollbackStocks(txCtx, committed)
|
||||
|
||||
_ = s.orders.OrderSetStatus(txCtx, id,
|
||||
pb.OrderStatus_ORDER_STATUS_FAILED.String())
|
||||
resErr = fmt.Errorf("stocks.StockReserve: %w", resErr)
|
||||
|
||||
resErr = fmt.Errorf("stocks.StockReserve: %w", err)
|
||||
return nil
|
||||
}
|
||||
committed = append(committed, st)
|
||||
}
|
||||
|
||||
return s.orders.OrderSetStatus(txCtx, id,
|
||||
pb.OrderStatus_ORDER_STATUS_AWAITING_PAYMENT.String())
|
||||
return nil
|
||||
})
|
||||
|
||||
finalStatus := pb.OrderStatus_ORDER_STATUS_AWAITING_PAYMENT.String()
|
||||
|
||||
defer func() {
|
||||
if statErr := s.setStatus(ctx, order.OrderID, finalStatus); statErr != nil {
|
||||
log.Error().Err(statErr).Msgf("failed to setStatus to %s", finalStatus)
|
||||
}
|
||||
}()
|
||||
|
||||
if err != nil {
|
||||
finalStatus = pb.OrderStatus_ORDER_STATUS_FAILED.String()
|
||||
|
||||
return 0, err
|
||||
}
|
||||
if resErr != nil {
|
||||
finalStatus = pb.OrderStatus_ORDER_STATUS_FAILED.String()
|
||||
|
||||
return 0, resErr
|
||||
}
|
||||
return orderID, nil
|
||||
|
||||
return order.OrderID, nil
|
||||
}
|
||||
|
||||
func (s *LomsService) OrderInfo(ctx context.Context, orderID entity.ID) (*entity.Order, error) {
|
||||
@@ -157,7 +208,7 @@ func (s *LomsService) OrderPay(ctx context.Context, orderID entity.ID) error {
|
||||
log.Error().Err(err).Msg("failed to free stock reservation")
|
||||
}
|
||||
}
|
||||
return s.orders.OrderSetStatus(txCtx, orderID,
|
||||
return s.setStatus(txCtx, orderID,
|
||||
pb.OrderStatus_ORDER_STATUS_PAYED.String())
|
||||
default:
|
||||
return model.ErrOrderInvalidStatus
|
||||
@@ -192,7 +243,7 @@ func (s *LomsService) OrderCancel(ctx context.Context, orderID entity.ID) error
|
||||
return err
|
||||
}
|
||||
}
|
||||
return s.orders.OrderSetStatus(txCtx, orderID,
|
||||
return s.setStatus(txCtx, orderID,
|
||||
pb.OrderStatus_ORDER_STATUS_CANCELLED.String())
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user