Spring Boot und Hystrix

19.06.2016

Spring Boot - Hystrix DateService mit Circuitbreaker

Hier wird gezeigt, wie mit Hystrix ein Circuit-Breaker mit Fallback mittels eines @HystrixCommand umgesetzt werden kann, um einen Remote-Call robuster zu gestalten. In dem Beispiel wird bei einem Remote-Service (http://www.timeapi.org/CET) das aktuelle Datum abgefragt. Lokal läuft eine Spring Boot Applikation, die über einen REST-Service auch eine Schnittstelle zum Abfragen des Datums zur Verfügung stellt, die mit einen Browser angesprochen wird. Im Fehlerfall wird über ein definierten Fallback das lokale Datum verwendet, um gegen den Ausfall des Remote-Service geschützt zu sein. Die lokale Spring Boot Applikation läuft unter dem Port 2001.

Spring Boot Applikation erstellen

Los geht es auf der Seite start.spring.io. Wo Web und Hystrix ausgewählt wird, um anschliessend das Projekt-Template zu erstellen.

Das Template wird anschliessend in einer IDE geöffnet und eine Klasse DateController angelegt, die eine REST-Schnittstelle zur Verfügung stellt, über die das Datum abgefragt werden kann.

package org.hameister;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

import java.text.DateFormatSymbols;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

/**
 * Created by hameister on 29.05.16.
 */
@RestController
@EnableHystrix
public class DateController {

    RestTemplate restTemplate = new RestTemplate();

    @HystrixCommand(commandKey = "circuitBreaker", fallbackMethod = "dateFallback")
    @RequestMapping(value = "/date", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
    ResponseEntity<String> getDate() {
        ResponseEntity<String> resp = null;
        try {
            resp = restTemplate.getForEntity("http://www.timeapi.org/CET", String.class);
        } catch (Exception e) {
            throw new RuntimeException("InternalServerError - Try Fallback");
        }

        return resp;
    }

    @HystrixCommand
    public ResponseEntity<String> dateFallback() {
        // 2016-06-11T12:44:26+01:00
        Date date = new Date();

        SimpleDateFormat outputFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", new DateFormatSymbols(Locale.GERMANY));
        String outputDate = outputFormat.format(date);

        return new ResponseEntity<String>("(Fallback):" + outputDate, HttpStatus.OK);
    }

}

Mit der Annotation @EnableHystrix wird Hystrix aktiviert. Wenn die Spring Boot Anwendung gestartet wird, kann das Datum über die URL http://localhost:2001/date abgefragt werden. Dies wurde im RequestMapping festgelegt.

In der Methode getDate() wird als erstes versucht das aktuelle Datum bei der URL http://www.timeapi.org/CET abzufragen. Wenn dabei ein Fehler auftritt, weil der Server nicht antwortet oder weil der lokale Rechner keine Verbindung zum Internet hat, dann wird die im Hystrix-Command (@HystrixCommand) definierte fallbackmethod aufgerufen. In dem Beispiel wird dann einfach das lokale Datum verwendet und lediglich umformatiert, so dass es das gleiche Format, wie die Server-Antwort hat.

Um lokal zu testen, ob der Fallback funktioniert, reicht es das WLAN am Rechner kurz abzuschalten und anschliessend mit den Aufruf in einem Browser durchzuführen.

Anmerkung: Damit die Spring Boot Applikation unter Port 2001 läuft muss in der Datei application.properties der Eintrag server.port=2001 ergänzt werden.