func()

in datasource/etcd/ms.go [59:157]


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
}