Ratpack с Hystrix

1. Въведение

Преди това показахме как да създадем високоефективно и реактивно приложение с Ratpack.

В тази статия ще разгледаме как да интегрираме Netflix Hystrix с приложение Ratpack.

Netflix Hystrix помага да се контролират взаимодействията между разпределени услуги, като се изолират точки за достъп, за да се спрат каскадните грешки и се предоставят резервни опции за толерантност към грешки. Това може да ни помогне да изградим по-устойчиво приложение. Вижте нашето въведение в Hystrix за бърз преглед.

И така, ние ще го използваме - ще подобрим нашето приложение Ratpack с тези полезни функции, предоставени от Hystrix.

2. Зависимост на Maven

За да използваме Hystrix с Ratpack, ни е необходима зависимостта ratpack-hystrix в проекта pom.xml :

 io.ratpack ratpack-hystrix 1.4.6 

Най-новата версия на ratpack-hystrix можете да намерите тук. Ratpack-hystrix включва сърцевина на ratpack и hystrix-core.

За да използваме реактивните характеристики на Ratpack, ще ни трябва и ratpack-rx:

 io.ratpack ratpack-rx 1.4.6 

Най-новата версия на ratpack-rx можете да намерите тук.

3. Сервиране с Hystrix Command

Когато използвате Hystrix, основните услуги обикновено са обвити в HystrixCommand или HystrixObservableCommand . Hystrix поддържа изпълнението на тези команди по начини на синхрон, асинхрон и реактив. Сред тях само реактивният е неблокиращ и официално препоръчителен.

В следващите примери ще изградим някои крайни точки, които извличат профил от Github REST API.

3.1. Изпълнение на реактивна команда

Първо, нека изградим реактивна бекенд услуга с Hystrix:

public class HystrixReactiveHttpCommand extends HystrixObservableCommand { //... @Override protected Observable construct() { return RxRatpack.observe(httpClient .get(uri, r -> r.headers(h -> h.add("User-Agent", "Baeldung HttpClient"))) .map(res -> res.getBody().getText())); } @Override protected Observable resumeWithFallback() { return Observable.just("eugenp's reactive fallback profile"); } }

Тук Ratpack реактивен HttpClient се използва, за да направи GET заявка. В HystrixReactiveHttpCommand може да изпълнява като реактивен манипулатор:

chain.get("rx", ctx -> new HystrixReactiveHttpCommand( ctx.get(HttpClient.class), eugenGithubProfileUri, timeout) .toObservable() .subscribe(ctx::render));

Крайната точка може да бъде проверена със следния тест:

@Test public void whenFetchReactive_thenGotEugenProfile() { assertThat(appUnderTest.getHttpClient().getText("rx"), containsString("www.baeldung.com")); }

3.2. Асинхронно изпълнение на команди

Асинхронното изпълнение на HystrixCommand поставя на опашка командата в пула от нишки и връща бъдеще :

chain.get("async", ctx -> ctx.render( new HystrixAsyncHttpCommand(eugenGithubProfileUri, timeout) .queue() .get()));

На HystrixAsyncHttpCommand изглежда така:

public class HystrixAsyncHttpCommand extends HystrixCommand { //... @Override protected String run() throws Exception { return EntityUtils.toString(HttpClientBuilder.create() .setDefaultRequestConfig(requestConfig) .setDefaultHeaders(Collections.singleton( new BasicHeader("User-Agent", "Baeldung Blocking HttpClient"))) .build().execute(new HttpGet(uri)).getEntity()); } @Override protected String getFallback() { return "eugenp's async fallback profile"; } }

Тук използваме блокиращ HttpClient вместо неблокиращ, защото искаме Hystrix да контролира времето за изпълнение на действителната команда, така че да няма нужда да се справяме сами, когато получаваме отговор от бъдещето . Това също така позволява на Hystrix да резервира или кешира нашата заявка.

Изпълнението на асинхрон също дава очакван резултат:

@Test public void whenFetchAsync_thenGotEugenProfile() { assertThat(appUnderTest.getHttpClient().getText("async"), containsString("www.baeldung.com")); }

3.3. Синхронно изпълнение на команди

Синхронното изпълнение изпълнява командата директно в текущата нишка:

chain.get("sync", ctx -> ctx.render( new HystrixSyncHttpCommand(eugenGithubProfileUri, timeout).execute()));

Внедряването на HystrixSyncHttpCommand е почти идентично с HystrixAsyncHttpCommand, с изключение на това, че ние му даваме различен резултат. Когато не пада назад, той се държи по същия начин като реактивното и асинхронното изпълнение:

@Test public void whenFetchSync_thenGotEugenProfile() { assertThat(appUnderTest.getHttpClient().getText("sync"), containsString("www.baeldung.com")); }

4. Метрики

Като регистрираме модула Guice - HystrixModule в регистъра на Ratpack, можем да предаваме показатели с обхват на заявката и да излагаме потоци от събития чрез GET крайна точка:

serverSpec.registry( Guice.registry(spec -> spec.module(new HystrixModule().sse()))) .handlers(c -> c.get("hystrix", new HystrixMetricsEventStreamHandler()));

В HystrixMetricsEventStreamHandler помага поток Hystrix показатели в текст / събитие поток формат, така че ние можем да проследявате показателите Hystrix Dashboard .

Можем да настроим самостоятелно табло за управление на Hystrix и да добавим нашия поток от събития Hystrix към списъка на монитора, за да видим как се представя нашето приложение Ratpack:

След няколко заявки към нашето приложение Ratpack, можем да видим свързаните с Hystrix команди в таблото.

4.1. Под капака

В HystrixModule , Hystrix Concurrency Strategy се регистрира с Hystrix чрез HystrixPlugin за управление на контекста на заявката с регистъра Ratpack. Това премахва необходимостта от инициализиране на контекста на заявката на Hystrix, преди всяка заявка да започне.

public class HystrixModule extends ConfigurableModule { //... @Override protected void configure() { try { HystrixPlugins.getInstance().registerConcurrencyStrategy( new HystrixRegistryBackedConcurrencyStrategy()); } catch (IllegalStateException e) { //... } } //... }

5. Заключение

В тази бърза статия показахме как Hystrix може да бъде интегриран в Ratpack и как да изтласкаме показателите на нашето приложение Ratpack към таблото за управление Hystrix за по-добър изглед на работата на приложението.

Както винаги, пълното внедряване може да бъде намерено в проекта Github.