diff --git a/lottery-client-java-se/src/com/example/lottery/client/LotteryAsyncClient.java b/lottery-client-java-se/src/com/example/lottery/client/LotteryAsyncClient.java new file mode 100644 index 0000000..2ff6067 --- /dev/null +++ b/lottery-client-java-se/src/com/example/lottery/client/LotteryAsyncClient.java @@ -0,0 +1,42 @@ +package com.example.lottery.client; + +import java.io.IOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * + * @author Binnur Kurt + * + */ +public class LotteryAsyncClient { + + private static final String URL = "http://localhost:8001/lottery/api/v1/numbers?column=10"; + + public static void main(String[] args) throws IOException, InterruptedException { + var counter = new AtomicInteger(0); + var client = HttpClient.newHttpClient(); + var request = HttpRequest.newBuilder().uri(URI.create(URL)).header("Accept", "application/json").build(); + + var start = System.currentTimeMillis(); + for (var i = 0; i < 1_000; ++i) { + // asynchronous call + client.sendAsync(request, HttpResponse.BodyHandlers.ofString()).thenApply(HttpResponse::body) + .thenAccept(numbers -> { + // System.out.println(Thread.currentThread().getName()); + var value = counter.incrementAndGet(); + if (value == 1_000) { + var stop = System.currentTimeMillis(); + System.err.println("Duration: " + (stop - start) + " ms."); + } + }); // functional programming + // System.out.println(numbers); + } + TimeUnit.SECONDS.sleep(10); + } + +} diff --git a/lottery-client-java-se/src/com/example/lottery/client/LotterySyncClient.java b/lottery-client-java-se/src/com/example/lottery/client/LotterySyncClient.java new file mode 100644 index 0000000..e78aee7 --- /dev/null +++ b/lottery-client-java-se/src/com/example/lottery/client/LotterySyncClient.java @@ -0,0 +1,37 @@ +package com.example.lottery.client; + +import java.io.IOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.util.stream.IntStream; + +/** + * + * @author Binnur Kurt + * + */ +public class LotterySyncClient { + + private static final String URL = "http://localhost:8001/lottery/api/v1/numbers?column=10"; + + public static void main(String[] args) throws IOException, InterruptedException { + var client = HttpClient.newHttpClient(); + var request = HttpRequest.newBuilder().uri(URI.create(URL)).header("Accept", "application/json").build(); + var start = System.currentTimeMillis(); + IntStream.range(0, 1_000).parallel().forEach(i -> { + // synchronous call + try { + // System.out.println(Thread.currentThread().getName()); + client.send(request, HttpResponse.BodyHandlers.ofString()).body(); + } catch (IOException | InterruptedException e) { + e.printStackTrace(); + } + // System.out.println(numbers); + }); + var stop = System.currentTimeMillis(); + System.err.println("Duration: " + (stop - start) + " ms."); + } + +} diff --git a/lottery-consumer-service/pom.xml b/lottery-consumer-service/pom.xml new file mode 100644 index 0000000..d54d0a7 --- /dev/null +++ b/lottery-consumer-service/pom.xml @@ -0,0 +1,99 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.3.1.RELEASE + + + com.example + lottery-consumer-service + 0.0.1-SNAPSHOT + lottery-consumer-service + Spring Boot Project for Lottery Consumer MicroService + + + 11 + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.retry + spring-retry + + + io.github.resilience4j + resilience4j-spring-boot2 + 1.5.0 + + + org.springframework.boot + spring-boot-starter-actuator + + + org.springframework.boot + spring-boot-devtools + runtime + true + + + org.springframework.boot + spring-boot-starter-test + test + + + org.junit.vintage + junit-vintage-engine + + + + + org.springframework.cloud + + spring-cloud-starter-netflix-eureka-client + + + + org.springframework.cloud + spring-cloud-starter-netflix-ribbon + + + org.springframework.cloud + spring-cloud-starter-openfeign + + + org.springframework.cloud + + spring-cloud-starter-netflix-hystrix + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + + + org.springframework.cloud + spring-cloud-dependencies + Hoxton.SR5 + pom + import + + + + diff --git a/lottery-consumer-service/src/main/java/com/example/lottery/LotteryConsumerServiceApplication.java b/lottery-consumer-service/src/main/java/com/example/lottery/LotteryConsumerServiceApplication.java new file mode 100644 index 0000000..139dfe0 --- /dev/null +++ b/lottery-consumer-service/src/main/java/com/example/lottery/LotteryConsumerServiceApplication.java @@ -0,0 +1,30 @@ +package com.example.lottery; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; +import org.springframework.cloud.netflix.eureka.EnableEurekaClient; +import org.springframework.cloud.netflix.hystrix.EnableHystrix; +import org.springframework.cloud.openfeign.EnableFeignClients; +import org.springframework.retry.annotation.EnableRetry; +import org.springframework.scheduling.annotation.EnableScheduling; + +/** + * + * @author Binnur Kurt + * + */ +@SpringBootApplication +@EnableScheduling +@EnableEurekaClient +@EnableDiscoveryClient +@EnableFeignClients +@EnableHystrix +@EnableRetry +public class LotteryConsumerServiceApplication { + + public static void main(String[] args) { + SpringApplication.run(LotteryConsumerServiceApplication.class, args); + } + +} diff --git a/lottery-consumer-service/src/main/java/com/example/lottery/client/FallbackLotteryService.java b/lottery-consumer-service/src/main/java/com/example/lottery/client/FallbackLotteryService.java new file mode 100644 index 0000000..9b37905 --- /dev/null +++ b/lottery-consumer-service/src/main/java/com/example/lottery/client/FallbackLotteryService.java @@ -0,0 +1,19 @@ +package com.example.lottery.client; + +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import org.springframework.stereotype.Service; + +import com.example.lottery.dto.LotteryResponse; + +@Service +public class FallbackLotteryService implements LotteryService { + + @Override + public LotteryResponse getLotteryNumbers(int column) { + return new LotteryResponse(IntStream.range(0, column).mapToObj(i -> List.of(1,2,3,4,5,6)).collect(Collectors.toList())); + } + +} diff --git a/lottery-consumer-service/src/main/java/com/example/lottery/client/LotteryService.java b/lottery-consumer-service/src/main/java/com/example/lottery/client/LotteryService.java new file mode 100644 index 0000000..94076ad --- /dev/null +++ b/lottery-consumer-service/src/main/java/com/example/lottery/client/LotteryService.java @@ -0,0 +1,13 @@ +package com.example.lottery.client; + +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; + +import com.example.lottery.dto.LotteryResponse; + +@FeignClient(name="lottery",fallback = FallbackLotteryService.class) +public interface LotteryService { + @GetMapping("/lottery/api/v1/numbers") + LotteryResponse getLotteryNumbers(@RequestParam int column); +} diff --git a/lottery-consumer-service/src/main/java/com/example/lottery/config/RestTemplateConfig.java b/lottery-consumer-service/src/main/java/com/example/lottery/config/RestTemplateConfig.java new file mode 100644 index 0000000..ed1e269 --- /dev/null +++ b/lottery-consumer-service/src/main/java/com/example/lottery/config/RestTemplateConfig.java @@ -0,0 +1,21 @@ +package com.example.lottery.config; + +import org.springframework.cloud.client.loadbalancer.LoadBalanced; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.client.RestTemplate; + +/** + * + * @author Binnur Kurt + * + */ +@Configuration +public class RestTemplateConfig { + + @Bean + @LoadBalanced + public RestTemplate restTemplate() { + return new RestTemplate(); + } +} diff --git a/lottery-consumer-service/src/main/java/com/example/lottery/dto/LotteryResponse.java b/lottery-consumer-service/src/main/java/com/example/lottery/dto/LotteryResponse.java new file mode 100644 index 0000000..fc3f0b7 --- /dev/null +++ b/lottery-consumer-service/src/main/java/com/example/lottery/dto/LotteryResponse.java @@ -0,0 +1,33 @@ +package com.example.lottery.dto; + +import java.util.List; + +/** + * + * @author Binnur Kurt + * + */ +public class LotteryResponse { + private List> numbers; + + public LotteryResponse() { + } + + public LotteryResponse(List> numbers) { + this.numbers = numbers; + } + + public List> getNumbers() { + return numbers; + } + + public void setNumbers(List> numbers) { + this.numbers = numbers; + } + + @Override + public String toString() { + return "LotteryResponse [numbers=" + numbers + "]"; + } + +} diff --git a/lottery-consumer-service/src/main/java/com/example/lottery/service/LotteryConsumerServiceLoadBalancing1.java b/lottery-consumer-service/src/main/java/com/example/lottery/service/LotteryConsumerServiceLoadBalancing1.java new file mode 100644 index 0000000..0427a21 --- /dev/null +++ b/lottery-consumer-service/src/main/java/com/example/lottery/service/LotteryConsumerServiceLoadBalancing1.java @@ -0,0 +1,47 @@ +package com.example.lottery.service; + +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; + +import javax.annotation.PostConstruct; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.cloud.client.discovery.DiscoveryClient; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +import com.example.lottery.dto.LotteryResponse; + +/** + * + * @author Binnur Kurt + * + */ +@Service +public class LotteryConsumerServiceLoadBalancing1 { + private static final String LOTTERY_SERVICE_URL = "http://%s:%d/lottery/api/v1/numbers?column=10"; + + @Autowired + private DiscoveryClient discoveryClient; + private List servers; + private AtomicInteger counter = new AtomicInteger(0); + private RestTemplate restTemplate; + + @PostConstruct + public void loadInstanceList() { + servers = discoveryClient.getInstances("lottery"); + servers.forEach(System.out::println); + this.restTemplate = new RestTemplate(); + } + + @Scheduled(fixedRate = 3_000) + public void callLotteryService() { + var index = counter.getAndIncrement() % servers.size(); + var server = servers.get(index); + var url = String.format(LOTTERY_SERVICE_URL, server.getHost(), server.getPort()); + var response = restTemplate.getForObject(url, LotteryResponse.class); + System.out.println(response); + } +} diff --git a/lottery-consumer-service/src/main/java/com/example/lottery/service/LotteryConsumerServiceLoadBalancing2.java b/lottery-consumer-service/src/main/java/com/example/lottery/service/LotteryConsumerServiceLoadBalancing2.java new file mode 100644 index 0000000..364974b --- /dev/null +++ b/lottery-consumer-service/src/main/java/com/example/lottery/service/LotteryConsumerServiceLoadBalancing2.java @@ -0,0 +1,50 @@ +package com.example.lottery.service; + +import java.util.stream.Collectors; + +import javax.annotation.PostConstruct; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.client.discovery.DiscoveryClient; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +import com.example.lottery.dto.LotteryResponse; +import com.netflix.loadbalancer.BaseLoadBalancer; +import com.netflix.loadbalancer.IRule; +import com.netflix.loadbalancer.LoadBalancerBuilder; +import com.netflix.loadbalancer.RoundRobinRule; +import com.netflix.loadbalancer.Server; + +/** + * + * @author Binnur Kurt + * + */ +@Service +public class LotteryConsumerServiceLoadBalancing2 { + private static final String LOTTERY_SERVICE_URL = "http://%s:%d/lottery/api/v1/numbers?column=10"; + @Autowired + private DiscoveryClient discoveryClient; + private BaseLoadBalancer loadBalancer; + private RestTemplate restTemplate; + + @PostConstruct + public void init() { + var servers = discoveryClient.getInstances("lottery").stream() + .map(instance -> new Server(instance.getHost(), instance.getPort())).collect(Collectors.toList()); + IRule roundRobinRule = new RoundRobinRule(); + loadBalancer = LoadBalancerBuilder.newBuilder().withRule(roundRobinRule) + .buildFixedServerListLoadBalancer(servers); + this.restTemplate = new RestTemplate(); + } + + @Scheduled(fixedRate = 3_000) + public void callLotteryService() { + var server = loadBalancer.chooseServer(); + String url = String.format(LOTTERY_SERVICE_URL, server.getHost(), server.getPort()); + LotteryResponse response = restTemplate.getForObject(url, LotteryResponse.class); + System.out.println(response); + } +} diff --git a/lottery-consumer-service/src/main/java/com/example/lottery/service/LotteryConsumerServiceLoadBalancing3.java b/lottery-consumer-service/src/main/java/com/example/lottery/service/LotteryConsumerServiceLoadBalancing3.java new file mode 100644 index 0000000..187244b --- /dev/null +++ b/lottery-consumer-service/src/main/java/com/example/lottery/service/LotteryConsumerServiceLoadBalancing3.java @@ -0,0 +1,27 @@ +package com.example.lottery.service; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +import com.example.lottery.dto.LotteryResponse; + +/** + * + * @author Binnur Kurt + * + */ +@Service +public class LotteryConsumerServiceLoadBalancing3 { + + private static final String LOTTERY_SERVICE_URL = "//lottery/lottery/api/v1/numbers?column=10"; + @Autowired + private RestTemplate restTemplate; + + @Scheduled(fixedRate = 3_000) + public void callLotteryService() { + LotteryResponse response = restTemplate.getForObject(LOTTERY_SERVICE_URL, LotteryResponse.class); + System.out.println(response); + } +} diff --git a/lottery-consumer-service/src/main/java/com/example/lottery/service/LotteryConsumerServiceLoadBalancing4.java b/lottery-consumer-service/src/main/java/com/example/lottery/service/LotteryConsumerServiceLoadBalancing4.java new file mode 100644 index 0000000..4dc0b8b --- /dev/null +++ b/lottery-consumer-service/src/main/java/com/example/lottery/service/LotteryConsumerServiceLoadBalancing4.java @@ -0,0 +1,24 @@ +package com.example.lottery.service; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; + +import com.example.lottery.client.LotteryService; + +/** + * + * @author Binnur Kurt + * + */ +@Service +public class LotteryConsumerServiceLoadBalancing4 { + + @Autowired + private LotteryService lotteryService; + + @Scheduled(fixedRate = 3_000) + public void callLotteryService() { + System.out.println(lotteryService.getLotteryNumbers(5)); + } +} diff --git a/lottery-consumer-service/src/main/java/com/example/lottery/service/LotteryConsumerServiceWithBulkHead.java b/lottery-consumer-service/src/main/java/com/example/lottery/service/LotteryConsumerServiceWithBulkHead.java new file mode 100644 index 0000000..e15bfce --- /dev/null +++ b/lottery-consumer-service/src/main/java/com/example/lottery/service/LotteryConsumerServiceWithBulkHead.java @@ -0,0 +1,33 @@ +package com.example.lottery.service; + +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +import com.example.lottery.dto.LotteryResponse; + +import io.github.resilience4j.bulkhead.annotation.Bulkhead; + +/** + * + * @author Binnur Kurt + * + */ +@Service +public class LotteryConsumerServiceWithBulkHead { + @Bulkhead(name = "lotterySrvBulkHead", fallbackMethod = "getFallbackEmployees", type = Bulkhead.Type.THREADPOOL) + public LotteryResponse getNumbers() { + System.err.println("Calling lottery service from LotteryConsumerServiceWithBulkHead..."); + RestTemplate rt = new RestTemplate(); + return rt.getForObject("http://localhost:8001/lottery/api/v1/numbers?column=10", LotteryResponse.class); + } + + public LotteryResponse getLotteryNumbersFallback(Exception e) { + System.err.println("getLotteryNumbersFallback()"); + return new LotteryResponse( + IntStream.range(0, 5).mapToObj(i -> List.of(10, 20, 25, 30, 40, 45)).collect(Collectors.toList())); + } +} \ No newline at end of file diff --git a/lottery-consumer-service/src/main/java/com/example/lottery/service/LotteryConsumerServiceWithCircuitBreaker.java b/lottery-consumer-service/src/main/java/com/example/lottery/service/LotteryConsumerServiceWithCircuitBreaker.java new file mode 100644 index 0000000..cd95f1f --- /dev/null +++ b/lottery-consumer-service/src/main/java/com/example/lottery/service/LotteryConsumerServiceWithCircuitBreaker.java @@ -0,0 +1,39 @@ +package com.example.lottery.service; + +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +import com.example.lottery.dto.LotteryResponse; + +import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker; + +/** + * + * @author Binnur Kurt + * + */ +@Service +public class LotteryConsumerServiceWithCircuitBreaker { + // integration client -> http -> Rest API (server) + // tomcat -> http/websocket (synchronous) -> (thread pool) + // capacity + // reactive system jetty -> http/websokcet (event queue, asynchronous) -> (thread pool) + // Fixed Thread Pool -> fixed (30) + // Cached Thread Pool -> variable + @CircuitBreaker(name="lotterySrvCircuitBreaker", + fallbackMethod = "getLotteryNumbersFallback") + public LotteryResponse getNumbers() { + System.err.println("Calling lottery service from LotteryClientWithCircuitBreaker..."); + RestTemplate rt = new RestTemplate(); + return rt.getForObject("http://localhost:8001/lottery/api/v1/numbers?column=10", LotteryResponse.class); + } + + public LotteryResponse getLotteryNumbersFallback(Exception e) { + System.err.println("getLotteryNumbersFallback()"); + return new LotteryResponse(IntStream.range(0, 5).mapToObj(i -> List.of(1,2,3,4,5,6)).collect(Collectors.toList())); + } +} \ No newline at end of file diff --git a/lottery-consumer-service/src/main/java/com/example/lottery/service/SimpleDemoService.java b/lottery-consumer-service/src/main/java/com/example/lottery/service/SimpleDemoService.java new file mode 100644 index 0000000..cbd990d --- /dev/null +++ b/lottery-consumer-service/src/main/java/com/example/lottery/service/SimpleDemoService.java @@ -0,0 +1,26 @@ +package com.example.lottery.service; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; + +/** + * + * @author Binnur Kurt + * + */ +@Service +public class SimpleDemoService { + @Autowired + private LotteryConsumerServiceWithCircuitBreaker srv; + + @Scheduled(fixedRate = 2_000) + public void doSomething() { + try { + System.out.println(srv.getNumbers()); + } catch (Exception e) { + System.err.println( + String.format("Exception (%s) in doSomething(): %s", e.getClass().getName(), e.getMessage())); + } + } +} diff --git a/lottery-consumer-service/src/main/java/com/example/lottery/service/StudyRetryStrategy.java b/lottery-consumer-service/src/main/java/com/example/lottery/service/StudyRetryStrategy.java new file mode 100644 index 0000000..cd0ed50 --- /dev/null +++ b/lottery-consumer-service/src/main/java/com/example/lottery/service/StudyRetryStrategy.java @@ -0,0 +1,28 @@ +package com.example.lottery.service; + +import java.net.SocketException; +import java.net.SocketTimeoutException; + +import org.springframework.retry.annotation.Backoff; +import org.springframework.retry.annotation.Retryable; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +import com.example.lottery.dto.LotteryResponse; + +/** + * + * @author Binnur Kurt + * + */ +@Service +public class StudyRetryStrategy { + + @Retryable(value= {SocketTimeoutException.class, SocketException.class}, + maxAttempts = 3, backoff=@Backoff(delay = 3_000)) + public LotteryResponse getNumbers() { + System.err.println("Calling lottery service from StudyRetryStrategy..."); + RestTemplate rt = new RestTemplate(); + return rt.getForObject("http://localhost:8001/lottery/api/v1/numbers?column=10", LotteryResponse.class); + } +} diff --git a/lottery-consumer-service/src/main/resources/application.properties b/lottery-consumer-service/src/main/resources/application.properties new file mode 100644 index 0000000..2428e89 --- /dev/null +++ b/lottery-consumer-service/src/main/resources/application.properties @@ -0,0 +1,22 @@ +server.address=localhost +server.port=5001 + +spring.application.name=lottery-consumer + +# eureka client configuration +eureka.client.serviceUrl.defaultZone=http://localhost:4040/eureka +eureka.instance.lease-expiration-duration-in-seconds=1 +eureka.instance.lease-renewal-interval-in-seconds=2 +eureka.instance.hostname=localhost +feign.hystrix.enabled=true + +# resilience4j configuration +resilience4j.circuitbreaker.configs.default.sliding-window-type=COUNT_BASED +resilience4j.circuitbreaker.configs.default.sliding-window-size=80 +resilience4j.circuitbreaker.configs.default.permitted-number-of-calls-in-half-open-state=14 +resilience4j.circuitbreaker.configs.default.wait-duration-in-open-state=10 +resilience4j.circuitbreaker.configs.default.failure-rate-threshold=60 +resilience4j.circuitbreaker.configs.default.register-health-indicator=true +resilience4j.circuitbreaker.configs.lotterySrvCircuitBreaker.baseConfig=default +resilience4j.bulkhead.instances.lotterySrvBulkHead.maxConcurrentCalls=10 +resilience4j.bulkhead.instances.lotterySrvBulkHead.maxWaitDuration=10ms \ No newline at end of file diff --git a/lottery-microservice/pom.xml b/lottery-microservice/pom.xml index c11a53c..f5f0a09 100644 --- a/lottery-microservice/pom.xml +++ b/lottery-microservice/pom.xml @@ -49,6 +49,12 @@ org.springframework.cloud spring-cloud-starter-config + + org.springframework.cloud + + spring-cloud-starter-netflix-eureka-client + + diff --git a/lottery-microservice/src/main/java/com/example/lottery/LotteryMicroserviceApplication.java b/lottery-microservice/src/main/java/com/example/lottery/LotteryMicroserviceApplication.java index b90d2d4..1b13bbb 100644 --- a/lottery-microservice/src/main/java/com/example/lottery/LotteryMicroserviceApplication.java +++ b/lottery-microservice/src/main/java/com/example/lottery/LotteryMicroserviceApplication.java @@ -2,12 +2,18 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; +import org.springframework.cloud.netflix.eureka.EnableEurekaClient; +// set PATH=c:\DEVEL\stage\opt\curl-7.45.0\bin;%PATH% +// curl localhost:8001/lottery/api/v1/actuator/refresh -X POST -d {} -H "Content-Type: application/json" @SpringBootApplication +@EnableEurekaClient +@EnableDiscoveryClient public class LotteryMicroserviceApplication { public static void main(String[] args) { SpringApplication.run(LotteryMicroserviceApplication.class, args); } -} +} \ No newline at end of file diff --git a/lottery-microservice/src/main/java/com/example/lottery/controller/LotteryRestController.java b/lottery-microservice/src/main/java/com/example/lottery/controller/LotteryRestController.java index 0da832e..04fac26 100644 --- a/lottery-microservice/src/main/java/com/example/lottery/controller/LotteryRestController.java +++ b/lottery-microservice/src/main/java/com/example/lottery/controller/LotteryRestController.java @@ -1,6 +1,8 @@ package com.example.lottery.controller; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; @@ -18,10 +20,15 @@ public class LotteryRestController { @Autowired private LotteryService lotteryService; + @Value("${server.address}") + private String host; + @Value("${server.port}") + private int port; // GET http://localhost:8001/lottery/api/v1/numbers?column=10 - @GetMapping(params = {"column"}) + @GetMapping(params = {"column"},produces = MediaType.APPLICATION_JSON_VALUE) public LotteryResponse getNumbers(@RequestParam int column){ + System.err.println(String.format("Lottery Service @ %s:%d is serving now...",host,port)); return new LotteryResponse(lotteryService.draw(column)); } } diff --git a/lottery-microservice/src/main/java/com/example/lottery/service/business/SimpleLotteryService.java b/lottery-microservice/src/main/java/com/example/lottery/service/business/SimpleLotteryService.java index 609a09b..7380b9c 100644 --- a/lottery-microservice/src/main/java/com/example/lottery/service/business/SimpleLotteryService.java +++ b/lottery-microservice/src/main/java/com/example/lottery/service/business/SimpleLotteryService.java @@ -6,11 +6,15 @@ import java.util.stream.IntStream; import org.springframework.beans.factory.annotation.Value; +import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.stereotype.Service; import com.example.lottery.service.LotteryService; +// set PATH=c:\DEVEL\stage\opt\curl-7.45.0\bin;%PATH% +// curl localhost:8001/lottery/api/v1/actuator/refresh -X POST -d {} -H "Content-Type: application/json" @Service +@RefreshScope // Spring Actuator -> REST POST public class SimpleLotteryService implements LotteryService{ @Value("${lottery.min}") private int lotteryMin; diff --git a/lottery-microservice/src/main/resources/application.properties b/lottery-microservice/src/main/resources/application.properties index 7a91bea..dc60fa2 100644 --- a/lottery-microservice/src/main/resources/application.properties +++ b/lottery-microservice/src/main/resources/application.properties @@ -8,4 +8,10 @@ spring.application.name=lottery spring.profiles.active=development # actuator -management.endpoints.web.exposure.include=* \ No newline at end of file +management.endpoints.web.exposure.include=* + +# eureka client configuration +eureka.client.serviceUrl.defaultZone=http://localhost:4040/eureka +eureka.instance.lease-expiration-duration-in-seconds=1 +eureka.instance.lease-renewal-interval-in-seconds=2 +eureka.instance.hostname=localhost \ No newline at end of file diff --git a/registry-service/src/main/java/com/example/RegistryServiceApplication.java b/registry-service/src/main/java/com/example/RegistryServiceApplication.java new file mode 100644 index 0000000..e28ef0b --- /dev/null +++ b/registry-service/src/main/java/com/example/RegistryServiceApplication.java @@ -0,0 +1,15 @@ +package com.example; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; + +@SpringBootApplication +@EnableEurekaServer +public class RegistryServiceApplication { + + public static void main(String[] args) { + SpringApplication.run(RegistryServiceApplication.class, args); + } + +} diff --git a/registry-service/src/main/resources/application.properties b/registry-service/src/main/resources/application.properties new file mode 100644 index 0000000..479d6f4 --- /dev/null +++ b/registry-service/src/main/resources/application.properties @@ -0,0 +1,11 @@ +server.address=localhost +server.port=4040 + +spring.application.name=registry-service + +# eureka server configuration +eureka.server.eviction-interval-timer-in-ms=2000 +eureka.client.fetch-registry=false +eureka.client.register-with-eureka=false +eureka.server.enable-self-preservation=false +eureka.instance.hostname=localhost \ No newline at end of file