private synchronized String getServiceBaseUrl() { if (serviceBaseUrl == null) { LoadBalancer lb = lbFactory.getLoadBalancer(serviceName); lb.waitForServiceInstance(); com.sixt.service.framework.rpc.ServiceEndpoint endpoint = lb.getHealthyInstance(); serviceBaseUrl = "http://" + endpoint.getHostAndPort(); } return serviceBaseUrl; }
protected void watchForUpdates() { List<ConsulHealthEntry> instancesHealth = loadCurrentHealthList(); LoadBalancerUpdate lbUpdate = diffServiceStatus(instancesHealth); if (! lbUpdate.isEmpty()) { loadbalancer.updateServiceEndpoints(lbUpdate); } }
public HttpRequestWrapper createHttpPost(RpcClient client) throws RpcCallException { this.client = client; ServiceEndpoint instance = loadBalancer.getHealthyInstance(); if (instance == null) { throw new RpcCallException(RpcCallException.Category.InternalServerError, "No available instance of " + loadBalancer.getServiceName()). withSource(serviceProps.getServiceName()); } return new HttpRequestWrapper("POST", instance); }
@Before public void setup() throws InterruptedException, ExecutionException, TimeoutException { when(loadBalancer.getHealthyInstance()).thenReturn(createServiceEndpoint()); when(loadBalancer.getHealthyInstanceExclude(anyListOf(ServiceEndpoint.class))) .thenReturn(createServiceEndpoint()); when(rpcClient.getRetries()).thenReturn(NUMBER_OF_RETRIES); when(rpcClient.getTimeout()).thenReturn(0); httpClientWrapper.setLoadBalancer(loadBalancer); when(rpcClientMetrics.getMethodTimer(any(), any())).thenReturn(new GoTimer("timer")); when(tracer.buildSpan(any())).thenReturn(spanBuilder); when(spanBuilder.start()).thenReturn(span); when(httpClient.newRequest(any(URI.class))).thenReturn(request); when(httpClient.newRequest(any(String.class))).thenReturn(request); when(request.content(any(ContentProvider.class))).thenReturn(request); when(request.method(anyString())).thenReturn(request); when(request.timeout(anyLong(), any(TimeUnit.class))).thenReturn(request); when(request.send()).thenReturn(httpContentResponse); when(httpContentResponse.getStatus()).thenReturn(100); dependencyHealthCheck = mock(ServiceDependencyHealthCheck.class); }
private HttpRequestWrapper createHttpPost(HttpRequestWrapper previous, List<ServiceEndpoint> triedEndpoints) throws RpcCallException { ServiceEndpoint instance = loadBalancer.getHealthyInstanceExclude(triedEndpoints); if (instance == null) { throw new RpcCallException(RpcCallException.Category.InternalServerError, "RpcCallException calling " + loadBalancer.getServiceName() + ", no available instance"). withSource(serviceProps.getServiceName()); } //TODO: There may still be a problem where retries are setting chunked encoding // or the content-length gets munged HttpRequestWrapper retval = new HttpRequestWrapper("POST", instance); retval.setHeaders(previous.getHeaders()); retval.setContentProvider(previous.getContentProvider()); return retval; }
public RESPONSE sendRequest(Message request, OrangeContext orangeContext) throws RpcCallException { ProtobufRpcRequest pbRequest = new ProtobufRpcRequest(client.getMethodName(), request); logger.info("Calling {} with {}", client.getMethodName(), ProtobufUtil. protobufToJson(pbRequest.getPayload())); client.getLoadBalancer().waitForServiceInstance(); RESPONSE response = null; response = (RESPONSE) client.callSynchronous(request, orangeContext); logger.info("Received response: {}", response); return response; }
/** * For each service monitored, create a thread that will grab the initial * info, then run a long-pool loop to get service updates from consul. */ public void monitorService(LoadBalancer lb) { this.loadBalancer = lb; RegistrationMonitorWorker worker = injector.getInstance(RegistrationMonitorWorker.class); worker.setLoadbalancer(loadBalancer); worker.setServiceName(lb.getServiceName()); Future future = executorService.submit(worker); workers.put(worker, future); }
public String callSynchronous(JsonArray params, OrangeContext orangeContext) throws RpcCallException { HttpClientWrapper clientWrapper = loadBalancer.getHttpClientWrapper(); HttpRequestWrapper balancedPost = clientWrapper.createHttpPost(this); //set custom headers if (orangeContext != null) { orangeContext.getProperties().forEach(balancedPost::setHeader); } balancedPost.setHeader("Content-type", TYPE_JSON); //TODO: fix: Temporary workaround below until go services are more http compliant balancedPost.setHeader("Connection", "close"); JsonRpcRequest jsonRequest = new JsonRpcRequest(null, methodName, params); String json = jsonRequest.toString(); balancedPost.setContentProvider(new StringContentProvider(json)); logger.debug("Sending request of size {}", json.length()); ContentResponse rpcResponse = clientWrapper.execute(balancedPost, new JsonRpcCallExceptionDecoder(), orangeContext); String rawResponse = rpcResponse.getContentAsString(); logger.debug("Json response from the service: {}", rawResponse); return JsonRpcResponse.fromString(rawResponse).getResult().getAsString(); }
private LoadBalancer buildLoadBalancer(String svc) { LoadBalancer retval = injector.getInstance(LoadBalancer.class); logger.debug("Returning instance of {} for the LoadBalancer instance", retval.getClass().getSimpleName()); retval.setServiceName(svc); loadBalancers.put(svc, retval); if (provider == null) { logger.warn("No ServiceDiscoveryProvider configured"); } else { provider.monitorService(retval); } return retval; }
private ServiceUnderTestImpl(String serviceName, boolean useEventHandler, String kafkaTopic) { ServiceProperties serviceProperties = new ServiceProperties(); serviceProperties.initialize(new String[0]); TestInjectionModule baseModule = new ServiceUnderTestModule(serviceName, serviceProperties); Injector injector = Guice.createInjector(baseModule, new ServiceRegistryModule(serviceProperties), new TracingModule(serviceProperties)); ServiceDiscoveryProvider provider = injector.getInstance(ServiceDiscoveryProvider.class); loadBalancerFactory = injector.getInstance(LoadBalancerFactory.class); loadBalancerFactory.initialize(provider); loadBalancer = loadBalancerFactory.getLoadBalancer(serviceName); loadBalancer.waitForServiceInstance(); RpcClientFactory rpcClientFactory = injector.getInstance(RpcClientFactory.class); RpcMethodScanner rpcMethodScanner = new RpcMethodScanner(rpcClientFactory); serviceMethods = rpcMethodScanner.getMethodHandlers(serviceName); httpCommandProxy = injector.getInstance(HttpCommandProxy.class); httpCommandProxy.setServiceName(serviceName); if (useEventHandler) { eventHandler = injector.getInstance(ServiceTestEventHandler.class); eventHandler.initialize(kafkaTopic); } }
Tags.PEER_SERVICE.set(span, loadBalancer.getServiceName()); span.setTag("rpc.call", client.getServiceMethodName()); if (orangeContext != null) {
public RESPONSE callSynchronous(Message request, OrangeContext orangeContext) throws RpcCallException { HttpClientWrapper clientWrapper = loadBalancer.getHttpClientWrapper(); HttpRequestWrapper balancedPost = clientWrapper.createHttpPost(this); //set custom headers if (orangeContext != null) { orangeContext.getProperties().forEach(balancedPost::setHeader); } balancedPost.setHeader("Content-type", TYPE_OCTET); //TODO: fix: Temporary workaround below until go services are more http compliant balancedPost.setHeader("Connection", "close"); ProtobufRpcRequest pbRequest = new ProtobufRpcRequest(methodName, request); byte[] protobufData = pbRequest.getProtobufData(); balancedPost.setContentProvider(new BytesContentProvider(protobufData)); logger.debug("Sending request of size {}", protobufData.length); ContentResponse rpcResponse = clientWrapper.execute(balancedPost, new ProtobufRpcCallExceptionDecoder(), orangeContext); byte[] data = rpcResponse.getContent(); logger.debug("Received a proto response of size: {}", data.length); return ProtobufUtil.byteArrayToProtobuf( new ProtobufRpcResponse(data).getPayloadData(), responseClass); }
protected void reportInitialServicesList(List<ConsulHealthEntry> instances) { LoadBalancerUpdate update = new LoadBalancerUpdate(); for (ConsulHealthEntry service : instances) { update.addNewService(newServiceEndpoint(service)); discoveredServices.put(service.getId(), service); } loadbalancer.updateServiceEndpoints(update); }
private void initialize() throws Exception { buildMethodHandlers(serviceName.replaceAll("-", "_")); registrationManager.setRegisteredHandlers(methodHandlers.getMethodHandlers()); registrationManager.register(); messageHandler.setServiceName(serviceName); messageHandler.start(); while(! registrationManager.isRegistered()) { logger.info("Waiting for service registration of {}", serviceName); new Sleeper().sleepNoException(100); } healthCheckManager.initialize(); loadBalancerFactory = injector.getInstance(LoadBalancerFactory.class); loadBalancerFactory.getLoadBalancer(serviceName).waitForServiceInstance(); }
@Test public void verifyMainLoop() { LoadBalancer lb = mock(LoadBalancer.class); worker.setLoadbalancer(lb); worker.shutdownSemaphore.release(); worker.sleeper = mock(Sleeper.class); when(response.getContentAsString()).thenReturn(null).thenReturn(healthInfo).thenReturn(healthInfo); worker.run(); verify(lb, times(1)).updateServiceEndpoints(any(LoadBalancerUpdate.class)); } }
@Test public void serviceFlappingAfterStartup() throws Exception { //there was a bug where if a consumed service went down and came back, there //were extra and incorrect updates posted to the lb //1. is available 2. becomes unavail 3. becomes avail again when(response.getContentAsString()).thenReturn(healthInfo).thenReturn(emptyHealthInfo). then((Answer<String>) invocation -> { worker.shutdownSemaphore.release(); return healthInfo; }); LoadBalancer lb = mock(LoadBalancer.class); worker.setLoadbalancer(lb); worker.sleeper = mock(Sleeper.class); worker.run(); ArgumentCaptor<LoadBalancerUpdate> captor = ArgumentCaptor.forClass(LoadBalancerUpdate.class); verify(lb, times(3)).updateServiceEndpoints(captor.capture()); assertThat(captor.getAllValues()).hasSize(3); }
@Test public void initialServiceReported() { List<ConsulHealthEntry> list = new ArrayList<>(); ConsulHealthEntry entry = new ConsulHealthEntry("1", ConsulHealthEntry.Status.Passing, "1.1.1.1", 1); list.add(entry); LoadBalancer lb = mock(LoadBalancer.class); worker.setLoadbalancer(lb); worker.reportInitialServicesList(list); assertThat(worker.discoveredServices).hasSize(1); verify(lb, times(1)).updateServiceEndpoints(any(LoadBalancerUpdate.class)); }
@Test public void serviceAppearsAfterStartup() throws Exception { //there was a bug where if a consumed service wasn't available at startup, //even when it came online later, it wouldn't be tracked. String emptyHealthInfo = "[]"; when(response.getContentAsString()).thenReturn(emptyHealthInfo). thenReturn(healthInfo); LoadBalancer lb = mock(LoadBalancer.class); worker.setLoadbalancer(lb); worker.shutdownSemaphore.release(); worker.sleeper = mock(Sleeper.class); worker.run(); ArgumentCaptor<LoadBalancerUpdate> captor = ArgumentCaptor.forClass(LoadBalancerUpdate.class); verify(lb, times(1)).updateServiceEndpoints(captor.capture()); assertThat(captor.getAllValues()).hasSize(1); LoadBalancerUpdate secondUpdate = captor.getAllValues().get(0); assertThat(secondUpdate.getNewServices()).isNotEmpty(); }