in datasource/etcd/ms.go [60:158]
func (ds *MetadataManager) RegisterService(ctx context.Context, request *pb.CreateServiceRequest) (
*pb.CreateServiceResponse, error) {
remoteIP := util.GetIPFromContext(ctx)
service := request.Service
serviceFlag := util.StringJoin([]string{
service.Environment, service.AppId, service.ServiceName, service.Version}, path.SPLIT)
domainProject := util.ParseDomainProject(ctx)
serviceKey := &pb.MicroServiceKey{
Tenant: domainProject,
Environment: service.Environment,
AppId: service.AppId,
ServiceName: service.ServiceName,
Alias: service.Alias,
Version: service.Version,
}
index := path.GenerateServiceIndexKey(serviceKey)
// 产生全局service id
requestServiceID := service.ServiceId
if len(requestServiceID) == 0 {
ctx = util.SetContext(ctx, uuid.ContextKey, index)
service.ServiceId = uuid.Generator().GetServiceID(ctx)
}
data, err := json.Marshal(service)
if err != nil {
log.Error(fmt.Sprintf("create micro-service[%s] failed, json marshal service failed, operator: %s",
serviceFlag, remoteIP), err)
return nil, pb.NewError(pb.ErrInternal, err.Error())
}
key := path.GenerateServiceKey(domainProject, service.ServiceId)
alias := path.GenerateServiceAliasKey(serviceKey)
opts := []etcdadpt.OpOptions{
etcdadpt.OpPut(etcdadpt.WithStrKey(key), etcdadpt.WithValue(data)),
etcdadpt.OpPut(etcdadpt.WithStrKey(index), etcdadpt.WithStrValue(service.ServiceId)),
}
uniqueCmpOpts := []etcdadpt.CmpOptions{
etcdadpt.NotExistKey(key),
etcdadpt.NotExistKey(index),
}
failOpts := []etcdadpt.OpOptions{
etcdadpt.OpGet(etcdadpt.WithStrKey(index)),
}
if len(serviceKey.Alias) > 0 {
opts = append(opts, etcdadpt.OpPut(etcdadpt.WithStrKey(alias), etcdadpt.WithStrValue(service.ServiceId)))
uniqueCmpOpts = append(uniqueCmpOpts, etcdadpt.NotExistKey(alias))
failOpts = append(failOpts, etcdadpt.OpGet(etcdadpt.WithStrKey(alias)))
}
syncOpts, err := esync.GenCreateOpts(ctx, datasource.ResourceService, request)
if err != nil {
log.Error("fail to create sync opts", err)
return nil, pb.NewError(pb.ErrInternal, err.Error())
}
opts = append(opts, syncOpts...)
resp, err := etcdadpt.TxnWithCmp(ctx, opts, uniqueCmpOpts, failOpts)
if err != nil {
log.Error(fmt.Sprintf("create micro-service[%s] failed, operator: %s",
serviceFlag, remoteIP), err)
return nil, pb.NewError(pb.ErrUnavailableBackend, err.Error())
}
if resp.Succeeded {
log.Info(fmt.Sprintf("create micro-service[%s][%s] successfully, operator: %s",
service.ServiceId, serviceFlag, remoteIP))
return &pb.CreateServiceResponse{
ServiceId: service.ServiceId,
}, nil
}
if len(requestServiceID) != 0 {
if len(resp.Kvs) == 0 || requestServiceID != util.BytesToStringWithNoCopy(resp.Kvs[0].Value) {
log.Warn(fmt.Sprintf("create micro-service[%s] failed, service already exists, operator: %s",
serviceFlag, remoteIP))
return nil, pb.NewError(pb.ErrServiceAlreadyExists,
"ServiceID conflict or found the same service with different id.")
}
}
if len(resp.Kvs) == 0 {
// internal error?
log.Error(fmt.Sprintf("create micro-service[%s] failed, unexpected txn response, operator: %s",
serviceFlag, remoteIP), nil)
return nil, pb.NewError(pb.ErrInternal, "Unexpected txn response.")
}
existServiceID := util.BytesToStringWithNoCopy(resp.Kvs[0].Value)
log.Warn(fmt.Sprintf("create micro-service[%s][%s] failed, service already exists, operator: %s",
existServiceID, serviceFlag, remoteIP))
return &pb.CreateServiceResponse{
ServiceId: existServiceID,
}, nil
}