Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -492,6 +492,60 @@ func (c *ProductColl) AddProductionService(productName, serviceName string) erro
return err
}

// AddServiceToFirstGroup atomically adds serviceName to services[0], initializing
// the first group when services is empty. Safe for concurrent callers.
func (c *ProductColl) AddServiceToFirstGroup(productName, serviceName string) error {
// Step 1: initialize the first group when services is empty.
_, _ = c.UpdateOne(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里错误被忽略了

context.TODO(),
bson.M{"product_name": productName, "services": bson.M{"$size": 0}},
bson.M{"$push": bson.M{"services": bson.A{serviceName}}},
)

// Step 2: append to services[0] only when the service is not already present in any group.
serviceUniqueFilter := bson.M{
"$elemMatch": bson.M{
"$elemMatch": bson.M{"$eq": serviceName},
},
}
_, err := c.UpdateOne(
context.TODO(),
bson.M{
"product_name": productName,
"services": bson.M{"$not": serviceUniqueFilter},
},
bson.M{"$addToSet": bson.M{"services.0": serviceName}},
)
return err
}

// AddProductionServiceToFirstGroup atomically adds serviceName to production_services[0],
// initializing the first group when production_services is empty. Safe for concurrent callers.
func (c *ProductColl) AddProductionServiceToFirstGroup(productName, serviceName string) error {
// Step 1: initialize the first group when production_services is empty.
_, _ = c.UpdateOne(
context.TODO(),
bson.M{"product_name": productName, "production_services": bson.M{"$size": 0}},
bson.M{"$push": bson.M{"production_services": bson.A{serviceName}}},
)

// Step 2: append to production_services[0] only when the service is not already present in any group.
serviceUniqueFilter := bson.M{
"$elemMatch": bson.M{
"$elemMatch": bson.M{"$eq": serviceName},
},
}
_, err := c.UpdateOne(
context.TODO(),
bson.M{
"product_name": productName,
"production_services": bson.M{"$not": serviceUniqueFilter},
},
bson.M{"$addToSet": bson.M{"production_services.0": serviceName}},
)
return err
}

// UpdateAll updates all projects in a bulk write.
// Currently, only field `shared_services` is supported.
// Note: A bulk operation can have at most 1000 operations, but the client will do it for us.
Expand Down
27 changes: 9 additions & 18 deletions pkg/microservice/aslan/core/service/service/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -628,25 +628,16 @@ func CreateServiceTemplate(userName string, args *commonmodels.Service, force bo
}

if notFoundErr != nil {
if productTempl, err := commonservice.GetProductTemplate(args.ProductName, log); err == nil {
//获取项目里面的所有服务
if production {
if len(productTempl.ProductionServices) > 0 && !sets.NewString(productTempl.ProductionServices[0]...).Has(args.ServiceName) {
productTempl.ProductionServices[0] = append(productTempl.ProductionServices[0], args.ServiceName)
} else {
productTempl.ProductionServices = [][]string{{args.ServiceName}}
}
} else {
if len(productTempl.Services) > 0 && !sets.NewString(productTempl.Services[0]...).Has(args.ServiceName) {
productTempl.Services[0] = append(productTempl.Services[0], args.ServiceName)
} else {
productTempl.Services = [][]string{{args.ServiceName}}
}
// Use atomic operations to avoid the read-modify-write race when multiple services
// are created concurrently for the same project.
if production {
if err := templaterepo.NewProductColl().AddProductionServiceToFirstGroup(args.ProductName, args.ServiceName); err != nil {
log.Errorf("CreateServiceTemplate update production orchestration %s error: %s", args.ServiceName, err)
return nil, e.ErrCreateTemplate.AddDesc(err.Error())
}
//更新项目模板
err = templaterepo.NewProductColl().Update(args.ProductName, productTempl)
if err != nil {
log.Errorf("CreateServiceTemplate Update %s error: %s", args.ServiceName, err)
} else {
if err := templaterepo.NewProductColl().AddServiceToFirstGroup(args.ProductName, args.ServiceName); err != nil {
log.Errorf("CreateServiceTemplate update orchestration %s error: %s", args.ServiceName, err)
return nil, e.ErrCreateTemplate.AddDesc(err.Error())
}
}
Expand Down
Loading