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

com.tencent.polaris.client.flow.GetResourcesInvoker Maven / Gradle / Ivy

/*
 * 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.client.flow;

import com.tencent.polaris.api.exception.ErrorCode;
import com.tencent.polaris.api.exception.PolarisException;
import com.tencent.polaris.api.exception.RetriableException;
import com.tencent.polaris.api.plugin.compose.Extensions;
import com.tencent.polaris.api.plugin.registry.EventCompleteNotifier;
import com.tencent.polaris.api.plugin.registry.LocalRegistry;
import com.tencent.polaris.api.plugin.registry.ResourceFilter;
import com.tencent.polaris.api.pojo.ServiceEventKey;
import com.tencent.polaris.api.pojo.ServiceEventKey.EventType;
import com.tencent.polaris.api.pojo.ServiceEventKeysProvider;
import com.tencent.polaris.api.pojo.ServiceInstances;
import com.tencent.polaris.api.pojo.ServiceRule;
import com.tencent.polaris.api.pojo.Services;
import com.tencent.polaris.api.utils.CollectionUtils;
import com.tencent.polaris.logging.LoggerFactory;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
import org.slf4j.Logger;

/**
 * 获取资源的回调
 */
public class GetResourcesInvoker implements EventCompleteNotifier, Future {

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

    private final ResourcesResponse resourcesResponse = new ResourcesResponse();

    private final Set listeningServices = new HashSet<>();

    private final int totalCallback;

    private final AtomicInteger responseIncrement = new AtomicInteger();

    private final Object notifier = new Object();

    private final Extensions extensions;

    private final boolean internalRequest;

    private final boolean useCache;

    public GetResourcesInvoker(ServiceEventKeysProvider paramProvider,
            Extensions extensions, boolean internalRequest, boolean useCache) throws PolarisException {
        this.extensions = extensions;
        this.internalRequest = internalRequest;
        this.totalCallback = init(paramProvider);
        this.useCache = useCache;
    }

    /**
     * 初始化invoker
     *
     * @param paramProvider
     * @return 等待的数量
     * @throws PolarisException
     */
    private int init(ServiceEventKeysProvider paramProvider) throws PolarisException {
        LocalRegistry localRegistry = extensions.getLocalRegistry();
        int callbacks = 0;
        if (!CollectionUtils.isEmpty(paramProvider.getSvcEventKeys())) {
            for (ServiceEventKey svcEventKey : paramProvider.getSvcEventKeys()) {
                listeningServices.add(svcEventKey);
                callbacks = processSvcEventKey(localRegistry, callbacks, svcEventKey);
            }
        }
        if (null != paramProvider.getSvcEventKey()) {
            listeningServices.add(paramProvider.getSvcEventKey());
            callbacks = processSvcEventKey(localRegistry, callbacks, paramProvider.getSvcEventKey());
        }
        return callbacks;
    }

    private int processSvcEventKey(LocalRegistry localRegistry, int callbacks, ServiceEventKey svcEventKey) {
        ResourceFilter filter = new ResourceFilter(svcEventKey, internalRequest, useCache);
        switch (svcEventKey.getEventType()) {
            case INSTANCE:
                ServiceInstances instances = localRegistry.getInstances(filter);
                if (instances.isInitialized()) {
                    resourcesResponse.addServiceInstances(svcEventKey, instances);
                } else {
                    localRegistry.loadInstances(svcEventKey, this);
                    callbacks++;
                }
                break;
            case SERVICE:
                Services services = localRegistry.getServices(filter);
                if (services.isInitialized()) {
                    resourcesResponse.addServices(svcEventKey, services);
                } else {
                    localRegistry.loadServices(svcEventKey, this);
                    callbacks++;
                }
                break;
            default:
                ServiceRule serviceRule = localRegistry.getServiceRule(filter);
                if (serviceRule.isInitialized()) {
                    resourcesResponse.addServiceRule(svcEventKey, serviceRule);
                } else {
                    localRegistry.loadServiceRule(svcEventKey, this);
                    callbacks++;
                }
                break;
        }
        return callbacks;
    }


    @Override
    public void complete(ServiceEventKey svcEventKey) {
        LocalRegistry localRegistry = extensions.getLocalRegistry();
        ResourceFilter filter = new ResourceFilter(svcEventKey, internalRequest, useCache);
        if (svcEventKey.getEventType() == ServiceEventKey.EventType.INSTANCE) {
            ServiceInstances instances = localRegistry.getInstances(filter);
            resourcesResponse.addServiceInstances(svcEventKey, instances);
        } else if (svcEventKey.getEventType() == EventType.SERVICE) {
            Services services = localRegistry.getServices(filter);
            resourcesResponse.addServices(svcEventKey, services);
        } else {
            ServiceRule serviceRule = localRegistry.getServiceRule(filter);
            resourcesResponse.addServiceRule(svcEventKey, serviceRule);
        }
        synchronized (notifier) {
            int curTotal = responseIncrement.addAndGet(1);
            if (totalCallback == curTotal) {
                notifier.notifyAll();
            }
        }
    }

    @Override
    public void completeExceptionally(ServiceEventKey svcEventKey, Throwable throwable) {
        resourcesResponse.addError(svcEventKey, throwable);
        synchronized (notifier) {
            int curTotal = responseIncrement.addAndGet(1);
            if (totalCallback == curTotal) {
                notifier.notifyAll();
            }
        }
    }

    @Override
    public boolean cancel(boolean mayInterruptIfRunning) {
        return false;
    }

    @Override
    public boolean isCancelled() {
        return false;
    }

    @Override
    public boolean isDone() {
        return totalCallback == 0 || responseIncrement.get() >= totalCallback;
    }

    @Override
    public ResourcesResponse get() throws InterruptedException, ExecutionException {
        if (!isDone()) {
            synchronized (notifier) {
                if (!isDone()) {
                    notifier.wait();
                }
            }
        }
        Map errors = resourcesResponse.getErrors();
        if (!errors.isEmpty()) {
            throw new ExecutionException(combineErrors(errors.values()));
        }
        return resourcesResponse;
    }

    @Override
    public ResourcesResponse get(
            long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
        long timeoutMs = TimeUnit.MILLISECONDS.convert(timeout, unit);
        if (!isDone()) {
            synchronized (notifier) {
                if (!isDone()) {
                    LOG.debug("start to wait for {}", this.listeningServices);
                    notifier.wait(timeoutMs);
                }
                LOG.debug("end to wait for {}", this.listeningServices);
                if (!isDone()) {
                    LOG.debug("timeout to wait for {}", this.listeningServices);
                    throw new TimeoutException();
                }
            }
        }
        Map errors = resourcesResponse.getErrors();
        if (!errors.isEmpty()) {
            throw new ExecutionException(combineErrors(errors.values()));
        }
        return resourcesResponse;
    }

    /**
     * 多个错误集成一个错误
     *
     * @return 集成的异常
     */
    private PolarisException combineErrors(Collection errors) {
        StringBuilder builder = new StringBuilder();
        int retryCount = 0;
        for (Throwable err : errors) {
            if (err instanceof RetriableException) {
                retryCount++;
            }
            builder.append(err.toString());
            builder.append("\n");
        }
        if (retryCount == errors.size()) {
            //全部都是重试,才进行重试
            return new RetriableException(ErrorCode.SERVER_USER_ERROR, builder.toString());
        }
        return new PolarisException(ErrorCode.SERVER_USER_ERROR, builder.toString());
    }

    /**
     * 资源回调监听
     */
    public interface ResourcesListener {

        /**
         * 当调用完成后回调
         *
         * @param response 应答信息
         */
        void onComplete(ResourcesResponse response);
    }

    ;
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy