Search in sources :

Example 1 with ServerOperation

use of com.netflix.loadbalancer.reactive.ServerOperation in project java-chassis by ServiceComb.

the class LoadbalanceHandler method sendWithRetry.

private void sendWithRetry(Invocation invocation, AsyncResponse asyncResp, final LoadBalancer choosenLB) throws Exception {
    long time = System.currentTimeMillis();
    // retry in loadbalance, 2.0 feature
    final int currentHandler = invocation.getHandlerIndex();
    final SyncResponseExecutor orginExecutor;
    final Executor newExecutor;
    if (invocation.getResponseExecutor() instanceof SyncResponseExecutor) {
        orginExecutor = (SyncResponseExecutor) invocation.getResponseExecutor();
        newExecutor = new Executor() {

            @Override
            public void execute(Runnable command) {
                // retry的场景,对于同步调用, 需要在网络线程中进行。同步调用的主线程已经被挂起,无法再主线程中进行重试。
                command.run();
            }
        };
        invocation.setResponseExecutor(newExecutor);
    } else {
        orginExecutor = null;
        newExecutor = null;
    }
    ExecutionListener<Invocation, Response> listener = new ExecutionListener<Invocation, Response>() {

        @Override
        public void onExecutionStart(ExecutionContext<Invocation> context) throws AbortExecutionException {
        }

        @Override
        public void onStartWithServer(ExecutionContext<Invocation> context, ExecutionInfo info) throws AbortExecutionException {
        }

        @Override
        public void onExceptionWithServer(ExecutionContext<Invocation> context, Throwable exception, ExecutionInfo info) {
            LOGGER.error("onExceptionWithServer msg {}; server {}", exception.getMessage(), context.getRequest().getEndpoint());
        }

        @Override
        public void onExecutionSuccess(ExecutionContext<Invocation> context, Response response, ExecutionInfo info) {
            if (orginExecutor != null) {
                orginExecutor.execute(() -> {
                    asyncResp.complete(response);
                });
            } else {
                asyncResp.complete(response);
            }
        }

        @Override
        public void onExecutionFailed(ExecutionContext<Invocation> context, Throwable finalException, ExecutionInfo info) {
            if (orginExecutor != null) {
                orginExecutor.execute(() -> {
                    asyncResp.consumerFail(finalException);
                });
            } else {
                asyncResp.consumerFail(finalException);
            }
        }
    };
    List<ExecutionListener<Invocation, Response>> listeners = new ArrayList<>(0);
    listeners.add(listener);
    ExecutionContext<Invocation> context = new ExecutionContext<>(invocation, null, null, null);
    LoadBalancerCommand<Response> command = LoadBalancerCommand.<Response>builder().withLoadBalancer(choosenLB).withServerLocator(invocation).withRetryHandler(new DefaultLoadBalancerRetryHandler(Configuration.INSTANCE.getRetryOnSame(invocation.getMicroserviceName()), Configuration.INSTANCE.getRetryOnNext(invocation.getMicroserviceName()), true)).withListeners(listeners).withExecutionContext(context).build();
    Observable<Response> observable = command.submit(new ServerOperation<Response>() {

        public Observable<Response> call(Server s) {
            return Observable.create(f -> {
                try {
                    ((CseServer) s).setLastVisitTime(time);
                    choosenLB.getLoadBalancerStats().incrementNumRequests(s);
                    invocation.setHandlerIndex(currentHandler);
                    invocation.setEndpoint(((CseServer) s).getEndpoint());
                    invocation.next(resp -> {
                        if (resp.isFailed()) {
                            LOGGER.error("service call error, msg is {}, server is {} ", ((Throwable) resp.getResult()).getMessage(), s);
                            choosenLB.getLoadBalancerStats().incrementSuccessiveConnectionFailureCount(s);
                            f.onError(resp.getResult());
                        } else {
                            choosenLB.getLoadBalancerStats().incrementActiveRequestsCount(s);
                            choosenLB.getLoadBalancerStats().noteResponseTime(s, (System.currentTimeMillis() - time));
                            f.onNext(resp);
                            f.onCompleted();
                        }
                    });
                } catch (Exception e) {
                    LOGGER.error("execution error, msg is " + e.getMessage());
                    f.onError(e);
                }
            });
        }
    });
    observable.subscribe(response -> {
    }, error -> {
    }, () -> {
    });
}
Also used : DefaultLoadBalancerRetryHandler(com.netflix.client.DefaultLoadBalancerRetryHandler) RoundRobinRule(com.netflix.loadbalancer.RoundRobinRule) LoggerFactory(org.slf4j.LoggerFactory) ExceptionUtils(io.servicecomb.core.exception.ExceptionUtils) SyncResponseExecutor(io.servicecomb.core.provider.consumer.SyncResponseExecutor) ArrayList(java.util.ArrayList) Observable(rx.Observable) IsolationServerListFilter(io.servicecomb.loadbalance.filter.IsolationServerListFilter) Map(java.util.Map) AbstractHandler(io.servicecomb.core.handler.impl.AbstractHandler) LoadBalancerCommand(com.netflix.loadbalancer.reactive.LoadBalancerCommand) Logger(org.slf4j.Logger) ExecutionListener(com.netflix.loadbalancer.reactive.ExecutionListener) Executor(java.util.concurrent.Executor) Server(com.netflix.loadbalancer.Server) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) AsyncResponse(io.servicecomb.core.AsyncResponse) TransactionControlFilter(io.servicecomb.loadbalance.filter.TransactionControlFilter) ExecutionContext(com.netflix.loadbalancer.reactive.ExecutionContext) List(java.util.List) IRule(com.netflix.loadbalancer.IRule) ExecutionInfo(com.netflix.loadbalancer.reactive.ExecutionInfo) Response(io.servicecomb.core.Response) ServerOperation(com.netflix.loadbalancer.reactive.ServerOperation) Invocation(io.servicecomb.core.Invocation) Invocation(io.servicecomb.core.Invocation) Server(com.netflix.loadbalancer.Server) SyncResponseExecutor(io.servicecomb.core.provider.consumer.SyncResponseExecutor) ArrayList(java.util.ArrayList) ExecutionInfo(com.netflix.loadbalancer.reactive.ExecutionInfo) ExecutionListener(com.netflix.loadbalancer.reactive.ExecutionListener) SyncResponseExecutor(io.servicecomb.core.provider.consumer.SyncResponseExecutor) Executor(java.util.concurrent.Executor) DefaultLoadBalancerRetryHandler(com.netflix.client.DefaultLoadBalancerRetryHandler) Observable(rx.Observable) AsyncResponse(io.servicecomb.core.AsyncResponse) Response(io.servicecomb.core.Response) ExecutionContext(com.netflix.loadbalancer.reactive.ExecutionContext)

Example 2 with ServerOperation

use of com.netflix.loadbalancer.reactive.ServerOperation in project incubator-servicecomb-java-chassis by apache.

the class LoadbalanceHandler method sendWithRetry.

private void sendWithRetry(Invocation invocation, AsyncResponse asyncResp, final LoadBalancer chosenLB) throws Exception {
    long time = System.currentTimeMillis();
    // retry in loadbalance, 2.0 feature
    final int currentHandler = invocation.getHandlerIndex();
    final SyncResponseExecutor orginExecutor;
    final Executor newExecutor;
    if (invocation.getResponseExecutor() instanceof SyncResponseExecutor) {
        orginExecutor = (SyncResponseExecutor) invocation.getResponseExecutor();
        newExecutor = new Executor() {

            @Override
            public void execute(Runnable command) {
                // retry的场景,对于同步调用, 同步调用的主线程已经被挂起,无法再主线程中进行重试;
                // 重试也不能在网络线程(event-loop)中进行,未被保护的阻塞操作会导致网络线程挂起
                RETRY_POOL.submit(command);
            }
        };
        invocation.setResponseExecutor(newExecutor);
    } else {
        orginExecutor = null;
        newExecutor = null;
    }
    ExecutionListener<Invocation, Response> listener = new ExecutionListener<Invocation, Response>() {

        @Override
        public void onExecutionStart(ExecutionContext<Invocation> context) throws AbortExecutionException {
        }

        @Override
        public void onStartWithServer(ExecutionContext<Invocation> context, ExecutionInfo info) throws AbortExecutionException {
        }

        @Override
        public void onExceptionWithServer(ExecutionContext<Invocation> context, Throwable exception, ExecutionInfo info) {
            LOGGER.error("onExceptionWithServer msg {}; server {}", exception.getMessage(), context.getRequest().getEndpoint());
        }

        @Override
        public void onExecutionSuccess(ExecutionContext<Invocation> context, Response response, ExecutionInfo info) {
            if (orginExecutor != null) {
                orginExecutor.execute(() -> {
                    asyncResp.complete(response);
                });
            } else {
                asyncResp.complete(response);
            }
        }

        @Override
        public void onExecutionFailed(ExecutionContext<Invocation> context, Throwable finalException, ExecutionInfo info) {
            if (orginExecutor != null) {
                orginExecutor.execute(() -> {
                    asyncResp.consumerFail(finalException);
                });
            } else {
                asyncResp.consumerFail(finalException);
            }
        }
    };
    List<ExecutionListener<Invocation, Response>> listeners = new ArrayList<>(0);
    listeners.add(listener);
    ExecutionContext<Invocation> context = new ExecutionContext<>(invocation, null, null, null);
    LoadBalancerCommand<Response> command = LoadBalancerCommand.<Response>builder().withLoadBalancer(chosenLB).withServerLocator(invocation).withRetryHandler(ExtensionsManager.createRetryHandler(invocation.getMicroserviceName())).withListeners(listeners).withExecutionContext(context).build();
    Observable<Response> observable = command.submit(new ServerOperation<Response>() {

        public Observable<Response> call(Server s) {
            return Observable.create(f -> {
                try {
                    ((CseServer) s).setLastVisitTime(time);
                    chosenLB.getLoadBalancerStats().incrementNumRequests(s);
                    // for retry
                    invocation.setHandlerIndex(currentHandler);
                    invocation.setEndpoint(((CseServer) s).getEndpoint());
                    invocation.next(resp -> {
                        if (resp.isFailed()) {
                            LOGGER.error("service call error, msg is {}, server is {} ", ((Throwable) resp.getResult()).getMessage(), s);
                            chosenLB.getLoadBalancerStats().incrementSuccessiveConnectionFailureCount(s);
                            ((CseServer) s).incrementContinuousFailureCount();
                            f.onError(resp.getResult());
                        } else {
                            chosenLB.getLoadBalancerStats().incrementActiveRequestsCount(s);
                            ((CseServer) s).clearContinuousFailure();
                            chosenLB.getLoadBalancerStats().noteResponseTime(s, (System.currentTimeMillis() - time));
                            f.onNext(resp);
                            f.onCompleted();
                        }
                    });
                } catch (Exception e) {
                    LOGGER.error("execution error, msg is " + e.getMessage());
                    f.onError(e);
                }
            });
        }
    });
    observable.subscribe(response -> {
    }, error -> {
    }, () -> {
    });
}
Also used : LoggerFactory(org.slf4j.LoggerFactory) DiscoveryTree(org.apache.servicecomb.serviceregistry.discovery.DiscoveryTree) AsyncResponse(org.apache.servicecomb.swagger.invocation.AsyncResponse) StringUtils(org.apache.commons.lang3.StringUtils) ArrayList(java.util.ArrayList) Observable(rx.Observable) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) TransactionControlFilter(org.apache.servicecomb.loadbalance.filter.TransactionControlFilter) CseServerDiscoveryFilter(org.apache.servicecomb.loadbalance.filter.CseServerDiscoveryFilter) Map(java.util.Map) LoadBalancerCommand(com.netflix.loadbalancer.reactive.LoadBalancerCommand) ConcurrentHashMapEx(org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx) ThreadFactory(java.util.concurrent.ThreadFactory) Response(org.apache.servicecomb.swagger.invocation.Response) ExecutorService(java.util.concurrent.ExecutorService) DiscoveryFilter(org.apache.servicecomb.serviceregistry.discovery.DiscoveryFilter) SyncResponseExecutor(org.apache.servicecomb.core.provider.consumer.SyncResponseExecutor) Logger(org.slf4j.Logger) ExecutionListener(com.netflix.loadbalancer.reactive.ExecutionListener) Executor(java.util.concurrent.Executor) Handler(org.apache.servicecomb.core.Handler) ExceptionUtils(org.apache.servicecomb.core.exception.ExceptionUtils) Server(com.netflix.loadbalancer.Server) VersionedCache(org.apache.servicecomb.foundation.common.cache.VersionedCache) Executors(java.util.concurrent.Executors) Invocation(org.apache.servicecomb.core.Invocation) ExecutionContext(com.netflix.loadbalancer.reactive.ExecutionContext) List(java.util.List) IsolationServerListFilter(org.apache.servicecomb.loadbalance.filter.IsolationServerListFilter) DiscoveryContext(org.apache.servicecomb.serviceregistry.discovery.DiscoveryContext) IRule(com.netflix.loadbalancer.IRule) ExecutionInfo(com.netflix.loadbalancer.reactive.ExecutionInfo) ServerOperation(com.netflix.loadbalancer.reactive.ServerOperation) Invocation(org.apache.servicecomb.core.Invocation) Server(com.netflix.loadbalancer.Server) SyncResponseExecutor(org.apache.servicecomb.core.provider.consumer.SyncResponseExecutor) ArrayList(java.util.ArrayList) ExecutionInfo(com.netflix.loadbalancer.reactive.ExecutionInfo) Observable(rx.Observable) ExecutionListener(com.netflix.loadbalancer.reactive.ExecutionListener) AsyncResponse(org.apache.servicecomb.swagger.invocation.AsyncResponse) Response(org.apache.servicecomb.swagger.invocation.Response) SyncResponseExecutor(org.apache.servicecomb.core.provider.consumer.SyncResponseExecutor) Executor(java.util.concurrent.Executor) ExecutionContext(com.netflix.loadbalancer.reactive.ExecutionContext)

Example 3 with ServerOperation

use of com.netflix.loadbalancer.reactive.ServerOperation in project ribbon by Netflix.

the class LoadBalancerCommandTest method testRetrySameServer.

@Test
public void testRetrySameServer() {
    BaseLoadBalancer loadBalancer = LoadBalancerBuilder.newBuilder().buildFixedServerListLoadBalancer(list);
    RetryHandler handler = new RetryHandler() {

        @Override
        public boolean isRetriableException(Throwable e, boolean sameServer) {
            return (e instanceof IllegalArgumentException);
        }

        @Override
        public boolean isCircuitTrippingException(Throwable e) {
            return false;
        }

        @Override
        public int getMaxRetriesOnSameServer() {
            return 3;
        }

        @Override
        public int getMaxRetriesOnNextServer() {
            return 0;
        }
    };
    LoadBalancerCommand<String> command = LoadBalancerCommand.<String>builder().withLoadBalancer(loadBalancer).withRetryHandler(handler).withServer(server1).build();
    ServerOperation<String> operation = new ServerOperation<String>() {

        AtomicInteger count = new AtomicInteger();

        @Override
        public Observable<String> call(final Server server) {
            return Observable.create(new OnSubscribe<String>() {

                @Override
                public void call(Subscriber<? super String> t1) {
                    if (count.incrementAndGet() < 3) {
                        t1.onError(new IllegalArgumentException());
                    } else {
                        t1.onNext(server.getHost());
                        t1.onCompleted();
                    }
                }
            });
        }
    };
    String result = command.submit(operation).toBlocking().single();
    assertEquals(3, loadBalancer.getLoadBalancerStats().getSingleServerStat(server1).getTotalRequestsCount());
    assertEquals("1", result);
}
Also used : AtomicInteger(java.util.concurrent.atomic.AtomicInteger) RetryHandler(com.netflix.client.RetryHandler) ServerOperation(com.netflix.loadbalancer.reactive.ServerOperation) Test(org.junit.Test)

Example 4 with ServerOperation

use of com.netflix.loadbalancer.reactive.ServerOperation in project ribbon by Netflix.

the class LoadBalancerCommandTest method testRetryNextServer.

@Test
public void testRetryNextServer() {
    BaseLoadBalancer loadBalancer = LoadBalancerBuilder.newBuilder().buildFixedServerListLoadBalancer(list);
    RetryHandler handler = new RetryHandler() {

        @Override
        public boolean isRetriableException(Throwable e, boolean sameServer) {
            return (e instanceof IllegalArgumentException);
        }

        @Override
        public boolean isCircuitTrippingException(Throwable e) {
            return false;
        }

        @Override
        public int getMaxRetriesOnSameServer() {
            return 1;
        }

        @Override
        public int getMaxRetriesOnNextServer() {
            return 5;
        }
    };
    ServerOperation<String> operation = new ServerOperation<String>() {

        AtomicInteger count = new AtomicInteger();

        @Override
        public Observable<String> call(final Server server) {
            return Observable.create(new OnSubscribe<String>() {

                @Override
                public void call(Subscriber<? super String> t1) {
                    if (count.incrementAndGet() < 3) {
                        t1.onError(new IllegalArgumentException());
                    } else {
                        t1.onNext(server.getHost());
                        t1.onCompleted();
                    }
                }
            });
        }
    };
    LoadBalancerCommand<String> command = LoadBalancerCommand.<String>builder().withLoadBalancer(loadBalancer).withRetryHandler(handler).build();
    String result = command.submit(operation).toBlocking().single();
    // server2 is picked first
    assertEquals("3", result);
    assertEquals(1, loadBalancer.getLoadBalancerStats().getSingleServerStat(server3).getTotalRequestsCount());
}
Also used : AtomicInteger(java.util.concurrent.atomic.AtomicInteger) RetryHandler(com.netflix.client.RetryHandler) ServerOperation(com.netflix.loadbalancer.reactive.ServerOperation) Test(org.junit.Test)

Example 5 with ServerOperation

use of com.netflix.loadbalancer.reactive.ServerOperation in project ribbon by Netflix.

the class LoadBalancingHttpClient method requestToOperation.

/**
 * Convert an HttpClientRequest to a ServerOperation
 *
 * @param request
 * @param rxClientConfig
 * @return
 */
protected ServerOperation<HttpClientResponse<O>> requestToOperation(final HttpClientRequest<I> request, final ClientConfig rxClientConfig) {
    Preconditions.checkNotNull(request);
    return new ServerOperation<HttpClientResponse<O>>() {

        final AtomicInteger count = new AtomicInteger(0);

        @Override
        public Observable<HttpClientResponse<O>> call(Server server) {
            HttpClient<I, O> rxClient = getOrCreateRxClient(server);
            setHostHeader(request, server.getHost());
            Observable<HttpClientResponse<O>> o;
            if (rxClientConfig != null) {
                o = rxClient.submit(request, rxClientConfig);
            } else {
                o = rxClient.submit(request);
            }
            return o.concatMap(new Func1<HttpClientResponse<O>, Observable<HttpClientResponse<O>>>() {

                @Override
                public Observable<HttpClientResponse<O>> call(HttpClientResponse<O> t1) {
                    if (t1.getStatus().code() / 100 == 4 || t1.getStatus().code() / 100 == 5)
                        return responseToErrorPolicy.call(t1, backoffStrategy.call(count.getAndIncrement()));
                    else
                        return Observable.just(t1);
                }
            });
        }
    };
}
Also used : Server(com.netflix.loadbalancer.Server) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) HttpClientResponse(io.reactivex.netty.protocol.http.client.HttpClientResponse) URI(java.net.URI) ServerOperation(com.netflix.loadbalancer.reactive.ServerOperation) Observable(rx.Observable)

Aggregations

ServerOperation (com.netflix.loadbalancer.reactive.ServerOperation)5 AtomicInteger (java.util.concurrent.atomic.AtomicInteger)4 Server (com.netflix.loadbalancer.Server)3 Observable (rx.Observable)3 RetryHandler (com.netflix.client.RetryHandler)2 IRule (com.netflix.loadbalancer.IRule)2 ExecutionContext (com.netflix.loadbalancer.reactive.ExecutionContext)2 ExecutionInfo (com.netflix.loadbalancer.reactive.ExecutionInfo)2 ExecutionListener (com.netflix.loadbalancer.reactive.ExecutionListener)2 LoadBalancerCommand (com.netflix.loadbalancer.reactive.LoadBalancerCommand)2 ArrayList (java.util.ArrayList)2 List (java.util.List)2 Map (java.util.Map)2 Executor (java.util.concurrent.Executor)2 Test (org.junit.Test)2 Logger (org.slf4j.Logger)2 LoggerFactory (org.slf4j.LoggerFactory)2 DefaultLoadBalancerRetryHandler (com.netflix.client.DefaultLoadBalancerRetryHandler)1 RoundRobinRule (com.netflix.loadbalancer.RoundRobinRule)1 HttpClientResponse (io.reactivex.netty.protocol.http.client.HttpClientResponse)1