All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.tencent.polaris.plugins.connector.consul.service.InstanceService Maven / Gradle / Ivy

There is a newer version: 2.0.0.0-RC3
Show newest version
/*
 * Tencent is pleased to support the open source community by making Polaris available.
 *
 * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
 *
 *  Licensed under the BSD 3-Clause License (the "License");
 *  you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://opensource.org/licenses/BSD-3-Clause
 *
 * Unless required by applicable law or agreed to in writing, software distributed
 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
 * CONDITIONS OF ANY KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 */

package com.tencent.polaris.plugins.connector.consul.service;

import com.ecwid.consul.SingleUrlParameters;
import com.ecwid.consul.UrlParameters;
import com.ecwid.consul.transport.HttpResponse;
import com.ecwid.consul.v1.ConsulClient;
import com.ecwid.consul.v1.ConsulRawClient;
import com.ecwid.consul.v1.OperationException;
import com.ecwid.consul.v1.QueryParams;
import com.ecwid.consul.v1.health.model.HealthService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.reflect.TypeToken;
import com.google.protobuf.BoolValue;
import com.google.protobuf.StringValue;
import com.google.protobuf.UInt32Value;
import com.tencent.polaris.api.exception.ErrorCode;
import com.tencent.polaris.api.exception.PolarisException;
import com.tencent.polaris.api.exception.ServerCodes;
import com.tencent.polaris.api.exception.ServerErrorResponseException;
import com.tencent.polaris.api.plugin.server.ServerEvent;
import com.tencent.polaris.api.utils.CollectionUtils;
import com.tencent.polaris.api.utils.StringUtils;
import com.tencent.polaris.logging.LoggerFactory;
import com.tencent.polaris.metadata.core.constant.TsfMetadataConstants;
import com.tencent.polaris.plugins.connector.common.ServiceUpdateTask;
import com.tencent.polaris.plugins.connector.consul.ConsulContext;
import com.tencent.polaris.specification.api.v1.model.ModelProto;
import com.tencent.polaris.specification.api.v1.service.manage.ResponseProto;
import com.tencent.polaris.specification.api.v1.service.manage.ServiceProto;
import org.slf4j.Logger;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import static com.ecwid.consul.json.GsonFactory.getGson;
import static com.tencent.polaris.api.config.plugin.DefaultPlugins.SERVER_CONNECTOR_CONSUL;
import static com.tencent.polaris.plugins.connector.consul.ConsulServerUtils.findHost;
import static com.tencent.polaris.plugins.connector.consul.ConsulServerUtils.getMetadata;

/**
 * @author Haotian Zhang
 */
public class InstanceService extends ConsulService {

    private static final Logger LOG = LoggerFactory.getLogger(InstanceService.class);

    private final Map serviceConsulIndexMap = new ConcurrentHashMap<>();

    public InstanceService(ConsulClient consulClient, ConsulRawClient consulRawClient, ConsulContext consulContext,
                           String threadName, ObjectMapper mapper) {
        super(consulClient, consulRawClient, consulContext, threadName, mapper);
    }

    @Override
    public void sendRequest(ServiceUpdateTask serviceUpdateTask) {
        String namespace = serviceUpdateTask.getServiceEventKey().getNamespace();
        String serviceId = serviceUpdateTask.getServiceEventKey().getService();
        String tag = consulContext.getQueryTag();
        String token = consulContext.getAclToken();
        boolean onlyPassing = consulContext.getQueryPassing();
        UrlParameters tokenParam = StringUtils.isNotBlank(token) ? new SingleUrlParameters("token", token) : null;
        UrlParameters tagParams = StringUtils.isNotBlank(tag) ? new SingleUrlParameters("tag", tag) : null;
        UrlParameters passingParams = onlyPassing ? new SingleUrlParameters("passing") : null;
        UrlParameters nsTypeParam = new SingleUrlParameters("nsType", "DEF_AND_GLOBAL");
        Long currentIndex = getServersConsulIndex(serviceId);
        int code = ServerCodes.DATA_NO_CHANGE;
        QueryParams queryParams = new QueryParams(consulContext.getWaitTime(), currentIndex);
        try {
            LOG.debug("Begin get service instances of {} sync", serviceId);
            HttpResponse rawResponse = consulRawClient.makeGetRequest("/v1/health/service/" + serviceId, tagParams,
                    passingParams, tokenParam, nsTypeParam, queryParams);
            if (rawResponse != null) {
                if (!currentIndex.equals(rawResponse.getConsulIndex())) {
                    code = ServerCodes.EXECUTE_SUCCESS;
                }
                LOG.debug("raw response: " + rawResponse.getContent() + " ; onlyPassing: " + onlyPassing);
                List value;
                if (rawResponse.getStatusCode() == 200) {
                    value = getGson().fromJson(rawResponse.getContent(),
                            new TypeToken>() {
                            }.getType());
                } else {
                    String rawResponseStr = "";
                    try {
                        rawResponseStr = mapper.writeValueAsString(rawResponse);
                    } catch (JsonProcessingException ignore) {
                    }
                    LOG.error("get service server list occur error. serviceId: {}. RawResponse: {}", serviceId,
                            rawResponseStr);
                    throw new OperationException(rawResponse);
                }
                ServiceProto.Service.Builder newServiceBuilder = ServiceProto.Service.newBuilder();
                newServiceBuilder.setNamespace(StringValue.of(namespace));
                newServiceBuilder.setName(StringValue.of(serviceUpdateTask.getServiceEventKey().getService()));
                newServiceBuilder.setRevision(StringValue.of(String.valueOf(rawResponse.getConsulIndex())));
                ServiceProto.Service service = newServiceBuilder.build();
                List instanceList = new ArrayList<>();
                if (CollectionUtils.isNotEmpty(value)) {
                    for (HealthService healthService : value) {
                        ServiceProto.Instance.Builder instanceBuilder = ServiceProto.Instance.newBuilder()
                                .setNamespace(StringValue.of(namespace))
                                .setService(StringValue.of(serviceId))
                                .setHost(StringValue.of(findHost(healthService)))
                                .setPort(UInt32Value.of(healthService.getService().getPort()))
                                .setHealthy(BoolValue.of(true))
                                .setIsolate(BoolValue.of(false));
                        // set Id
                        if (StringUtils.isNotBlank(healthService.getService().getId())) {
                            instanceBuilder.setId(StringValue.of(healthService.getService().getId()));
                        } else {
                            String id =
                                    serviceId + "-" + findHost(healthService).replace(".", "-") + "-" + healthService.getService().getPort();
                            instanceBuilder.setId(StringValue.of(id));
                            LOG.info("Instance with name {} host {} port {} doesn't have id.", serviceId
                                    , findHost(healthService), healthService.getService().getPort());
                        }
                        // set metadata
                        Map metadata = getMetadata(healthService);
                        if (CollectionUtils.isNotEmpty(metadata)) {
                            instanceBuilder.putAllMetadata(metadata);
                        }
                        // set location
                        ModelProto.Location.Builder locationBuilder = ModelProto.Location.newBuilder();
                        if (metadata.containsKey(TsfMetadataConstants.TSF_ZONE)) {
                            locationBuilder.setZone(StringValue.of(metadata.get(TsfMetadataConstants.TSF_ZONE)));
                        }
                        if (metadata.containsKey(TsfMetadataConstants.TSF_REGION)) {
                            locationBuilder.setRegion(StringValue.of(metadata.get(TsfMetadataConstants.TSF_REGION)));
                        }
                        instanceBuilder.setLocation(locationBuilder.build());
                        instanceList.add(instanceBuilder.build());
                    }
                }

                ResponseProto.DiscoverResponse.Builder newDiscoverResponseBuilder = ResponseProto.DiscoverResponse.newBuilder();
                newDiscoverResponseBuilder.setService(service);
                newDiscoverResponseBuilder.addAllInstances(instanceList);
                newDiscoverResponseBuilder.setCode(UInt32Value.of(code));

                ServerEvent serverEvent = new ServerEvent(serviceUpdateTask.getServiceEventKey(), newDiscoverResponseBuilder.build(), null, SERVER_CONNECTOR_CONSUL);
                boolean svcDeleted = serviceUpdateTask.notifyServerEvent(serverEvent);
                // 即使无服务,也要更新 index
                if (rawResponse.getConsulIndex() != null) {
                    setServersConsulIndex(serviceId, currentIndex, rawResponse.getConsulIndex());
                }
                if (!svcDeleted) {
                    serviceUpdateTask.addUpdateTaskSet();
                }
            }
        } catch (Throwable throwable) {
            LOG.error("Get service instances of {} sync failed. Will sleep for {} ms.", serviceId, consulContext.getConsulErrorSleep(), throwable);
            try {
                Thread.sleep(consulContext.getConsulErrorSleep());
            } catch (Exception e1) {
                LOG.error("error in sleep, msg: " + e1.getMessage());
            }
            PolarisException error = ServerErrorResponseException.build(ErrorCode.NETWORK_ERROR.getCode(),
                    String.format("Get service instances of %s sync failed.",
                            serviceUpdateTask.getServiceEventKey().getServiceKey()));
            ServerEvent serverEvent = new ServerEvent(serviceUpdateTask.getServiceEventKey(), null, error, SERVER_CONNECTOR_CONSUL);
            serviceUpdateTask.notifyServerEvent(serverEvent);
            serviceUpdateTask.retry();
        }
    }

    private Long getServersConsulIndex(String serviceId) {
        Long index = serviceConsulIndexMap.get(serviceId);
        if (index != null) {
            return index;
        }
        setServersConsulIndex(serviceId, null, -1L);
        return -1L;
    }

    private void setServersConsulIndex(String serviceId, Long lastIndex, Long newIndex) {
        LOG.debug("serviceId: {}; lastIndex: {}; newIndex: {}", serviceId, lastIndex, newIndex);
        serviceConsulIndexMap.put(serviceId, newIndex);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy