From 28d1cfc160939cd3928a24184d36b9e459818a8f Mon Sep 17 00:00:00 2001 From: mlogclub Date: Tue, 28 Apr 2026 23:03:06 +0800 Subject: [PATCH] fix(customer_service): update EnsureExternalCustomer to use TxContext --- internal/services/conversation_service.go | 2 +- internal/services/customer_service.go | 32 +++++++++++++------ internal/services/customer_service_test.go | 32 ++++++++++++------- internal/services/customer_session_service.go | 2 +- 4 files changed, 44 insertions(+), 24 deletions(-) diff --git a/internal/services/conversation_service.go b/internal/services/conversation_service.go index 995b5a3..e554058 100644 --- a/internal/services/conversation_service.go +++ b/internal/services/conversation_service.go @@ -109,7 +109,7 @@ func (s *conversationService) Create(externalUser openidentity.ExternalUser, cha var conversation *models.Conversation created := false if err := sqls.WithTransaction(func(ctx *sqls.TxContext) error { - customerID, err := CustomerService.EnsureExternalCustomer(ctx.Tx, externalUser) + customerID, err := CustomerService.EnsureExternalCustomer(ctx, externalUser) if err != nil { return err } diff --git a/internal/services/customer_service.go b/internal/services/customer_service.go index e4dccca..b6f0590 100644 --- a/internal/services/customer_service.go +++ b/internal/services/customer_service.go @@ -113,14 +113,17 @@ func (s *customerService) CountByCompanyIDs(companyIDs []int64) map[int64]int64 return repositories.CustomerRepository.CountByCompanyIDs(sqls.DB(), companyIDs, int(enums.StatusDeleted)) } -func (s *customerService) EnsureExternalCustomer(db *gorm.DB, externalUser openidentity.ExternalUser) (int64, error) { +func (s *customerService) EnsureExternalCustomer(ctx *sqls.TxContext, externalUser openidentity.ExternalUser) (int64, error) { + if ctx == nil || ctx.Tx == nil { + return 0, errorsx.InvalidParam("事务上下文不能为空") + } externalSource := externalUser.ExternalSource externalID := strings.TrimSpace(externalUser.ExternalID) if strings.TrimSpace(string(externalSource)) == "" || externalID == "" { return 0, errorsx.Unauthorized("外部用户标识不能为空") } now := time.Now() - if identity := repositories.CustomerIdentityRepository.GetBy(db, externalSource, externalID); identity != nil { + if identity := repositories.CustomerIdentityRepository.GetBy(ctx.Tx, externalSource, externalID); identity != nil { updates := map[string]any{ "last_active_at": now, "updated_at": now, @@ -128,14 +131,23 @@ func (s *customerService) EnsureExternalCustomer(db *gorm.DB, externalUser openi if strs.IsNotBlank(externalUser.ExternalName) { updates["name"] = externalUser.ExternalName } - if err := repositories.CustomerRepository.Updates(db, identity.CustomerID, updates); err != nil { + if err := repositories.CustomerRepository.Updates(ctx.Tx, identity.CustomerID, updates); err != nil { return 0, err } - if strs.IsNotBlank(externalUser.ExternalName) { - if err := s.syncConversationCustomerName(db, identity.CustomerID, externalUser.ExternalName, nil, now); err != nil { - return 0, err - } - } + + ctx.RegisterCallback(func() { + go func() { + if strs.IsNotBlank(externalUser.ExternalName) { + if err := s.syncConversationCustomerName(sqls.DB(), identity.CustomerID, externalUser.ExternalName, nil, now); err != nil { + slog.Error("sync conversation customer name failed", + "customerId", identity.CustomerID, + "customerName", externalUser.ExternalName, + "error", err, + ) + } + } + }() + }) return identity.CustomerID, nil } @@ -145,10 +157,10 @@ func (s *customerService) EnsureExternalCustomer(db *gorm.DB, externalUser openi Status: enums.StatusOk, AuditFields: utils.BuildAuditFields(nil), } - if err := repositories.CustomerRepository.Create(db, customer); err != nil { + if err := repositories.CustomerRepository.Create(ctx.Tx, customer); err != nil { return 0, err } - if err := repositories.CustomerIdentityRepository.Create(db, &models.CustomerIdentity{ + if err := repositories.CustomerIdentityRepository.Create(ctx.Tx, &models.CustomerIdentity{ CustomerID: customer.ID, ExternalSource: externalSource, ExternalID: externalID, diff --git a/internal/services/customer_service_test.go b/internal/services/customer_service_test.go index 25a44ba..a9aab68 100644 --- a/internal/services/customer_service_test.go +++ b/internal/services/customer_service_test.go @@ -18,12 +18,16 @@ import ( func TestEnsureExternalCustomerUpdatesNameFromExternalIdentity(t *testing.T) { db := setupCustomerServiceTestDB(t) - firstID, err := services.CustomerService.EnsureExternalCustomer(db, openidentity.ExternalUser{ - ExternalSource: enums.ExternalSourceUser, - ExternalID: "user-1", - ExternalName: "张三", - }) - if err != nil { + var firstID int64 + if err := sqls.WithTransaction(func(ctx *sqls.TxContext) error { + id, err := services.CustomerService.EnsureExternalCustomer(ctx, openidentity.ExternalUser{ + ExternalSource: enums.ExternalSourceUser, + ExternalID: "user-1", + ExternalName: "张三", + }) + firstID = id + return err + }); err != nil { t.Fatalf("EnsureExternalCustomer() first error = %v", err) } @@ -37,12 +41,16 @@ func TestEnsureExternalCustomerUpdatesNameFromExternalIdentity(t *testing.T) { t.Fatalf("create conversation error = %v", err) } - secondID, err := services.CustomerService.EnsureExternalCustomer(db, openidentity.ExternalUser{ - ExternalSource: enums.ExternalSourceUser, - ExternalID: "user-1", - ExternalName: "李四", - }) - if err != nil { + var secondID int64 + if err := sqls.WithTransaction(func(ctx *sqls.TxContext) error { + id, err := services.CustomerService.EnsureExternalCustomer(ctx, openidentity.ExternalUser{ + ExternalSource: enums.ExternalSourceUser, + ExternalID: "user-1", + ExternalName: "李四", + }) + secondID = id + return err + }); err != nil { t.Fatalf("EnsureExternalCustomer() second error = %v", err) } if secondID != firstID { diff --git a/internal/services/customer_session_service.go b/internal/services/customer_session_service.go index 944b0bc..5a91f89 100644 --- a/internal/services/customer_session_service.go +++ b/internal/services/customer_session_service.go @@ -57,7 +57,7 @@ func (s *customerSessionService) Exchange(channel *models.Channel, externalUser } var customerID int64 if err := sqls.WithTransaction(func(ctx *sqls.TxContext) error { - id, err := CustomerService.EnsureExternalCustomer(ctx.Tx, externalUser) + id, err := CustomerService.EnsureExternalCustomer(ctx, externalUser) if err != nil { return err }