{"action":"created","issue":{"url":"https://api.github.com/repos/spring-cloud/spring-cloud-netflix/issues/1290","repository_url":"https://api.github.com/repos/spring-cloud/spring-cloud-netflix","labels_url":"https://api.github.com/repos/spring-cloud/spring-cloud-netflix/issues/1290/labels{/name}","comments_url":"https://api.github.com/repos/spring-cloud/spring-cloud-netflix/issues/1290/comments","events_url":"https://api.github.com/repos/spring-cloud/spring-cloud-netflix/issues/1290/events","html_url":"https://github.com/spring-cloud/spring-cloud-netflix/issues/1290","id":172745235,"number":1290,"title":"Best practices for using Eureka for 0-downtime Blue/Green deployments","user":{"login":"william-tran","id":1084441,"avatar_url":"https://avatars.githubusercontent.com/u/1084441?v=3","gravatar_id":"","url":"https://api.github.com/users/william-tran","html_url":"https://github.com/william-tran","followers_url":"https://api.github.com/users/william-tran/followers","following_url":"https://api.github.com/users/william-tran/following{/other_user}","gists_url":"https://api.github.com/users/william-tran/gists{/gist_id}","starred_url":"https://api.github.com/users/william-tran/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/william-tran/subscriptions","organizations_url":"https://api.github.com/users/william-tran/orgs","repos_url":"https://api.github.com/users/william-tran/repos","events_url":"https://api.github.com/users/william-tran/events{/privacy}","received_events_url":"https://api.github.com/users/william-tran/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":1,"created_at":"2016-08-23T16:25:48Z","updated_at":"2016-08-23T18:20:20Z","closed_at":null,"body":"This issue is more of a discussion that I want to open up to the community so we can figure this out. The goal is to use Eureka to facilitate blue-green deployments with 0 downtime. \r\n\r\n# Example 1: From application code\r\n\r\nSay you have 2 instances of an app deployed using two distinct uris:\r\n\r\n```\r\nspring.application.name: api\r\n\r\n---\r\nspring.profiles: blue\r\neureka.instance.hostname: api-blue.example.com\r\n\r\n---\r\nspring.profiles: green\r\neureka.instance.hostname: api-green.example.com\r\n\r\n```\r\n\r\nLet's say both are up and healthy. You have a client app my-app that needs to make requests to api:\r\n\r\n```\r\n@RestController\r\n@SpringBootApplication\r\n@EnableDiscoveryClient\r\npublic class MyApp {\r\n\r\n\t@Bean\r\n\t@LoadBalanced\r\n\tpublic RestTemplate restTemplate() {\r\n\t\treturn new RestTemplate();\r\n\t}\r\n\r\n\t@RequestMapping(\"/hit-api\")\r\n\tpublic Object hitApi() {\r\n\t\treturn restTemplate().getForObject(\"https://api/something\", Object.class);\r\n\t}\r\n\r\n```\r\n\r\nWhen green-api.example.com goes down for upgrade, it gracefully shuts down and deletes its registration from Eureka. my-app won't know this happened until it fetches the registry again, which happens every 30 seconds by default. So for up to 30 seconds, the `@LoadBalanced` RestTemplate will send requests to `api-green.example.com` even though its down. \r\n\r\nThere are a few things we can do:\r\n\r\n## Use Ribbon's support for retry\r\n\r\nThis doesn't work out of the box because the `@LoadBalanced` RestTemplate doesn't use Netflix's RestClient and related classes, which provide the retry functionality. One of the reasons for not using it is because it's deprecated, and doesn't support PATCH.\r\n\r\n## Use Spring Retry\r\n\r\nBy adding the following to my project:\r\n\r\n```\r\n\tcompile(\"org.springframework.boot:spring-boot-starter-aop\")\r\n\tcompile(\"org.springframework.retry:spring-retry\")\r\n```\r\n\r\n```\r\n// ...\r\n@EnableRetry\r\npublic class MyApp {\r\n// ...\r\n\t@Retryable\r\n\t@RequestMapping(\"/hit-api\")\r\n\tpublic Object hitApi() {\r\n// ...\r\n```\r\n\r\nA request made to `api-green.example.com` will error out, the RestTemplate with throw an exception, that exception breaks out of the `@Retryable` method and the method is executed again. Because the `@LoadBalanced` RestTemplate round robins, the next method execution tries a different server, api-blue.example.com which is still up. This works great. \r\n\r\nThe default is to retry on any exception, but you may need to narrow down which exceptions should be retried. In CloudFoundry, you get a 404 when the app is down, so to zero-in on such a HttpClientErrorException, it looks like you'll need to write a [RetryPolicy](https://github.com/spring-projects/spring-retry#retry-policies) which I haven't attempted. \r\n\r\n# Example 2: From Zuul\r\n\r\nLet's say we've configured Zuul to proxy to apps registered with Eureka, and are using its retry support provided by Netflix classes:\r\n\r\n```\r\n@SpringBootApplication\r\n@EnableDiscoveryClient\r\n@EnableZuulProxy\r\npublic class ApiGatewayApplication {\r\n\r\n\tpublic static void main(String[] args) {\r\n\t\tSpringApplication.run(ApiGatewayApplication.class, args);\r\n\t}\r\n}\r\n```\r\n\r\n```\r\nzuul:\r\n  routes:\r\n    api:\r\n      path: /api/**\r\n      serviceId: api\r\n      retryable: true\r\n```\r\n\r\nHere's where I got stuck, at least in CloudFoundry, because the 404 doesn't get handled by the retry logic in [RequestSpecificRetryHandler](https://github.com/Netflix/ribbon/blob/v2.2.0/ribbon-core/src/main/java/com/netflix/client/RequestSpecificRetryHandler.java#L54-L69) and I don't see a way of customizing this as well.\r\n\r\nDoes anyone else have experiences to share in doing blue/green with Spring Cloud Netflix projects?  "},"comment":{"url":"https://api.github.com/repos/spring-cloud/spring-cloud-netflix/issues/comments/241826194","html_url":"https://github.com/spring-cloud/spring-cloud-netflix/issues/1290#issuecomment-241826194","issue_url":"https://api.github.com/repos/spring-cloud/spring-cloud-netflix/issues/1290","id":241826194,"user":{"login":"william-tran","id":1084441,"avatar_url":"https://avatars.githubusercontent.com/u/1084441?v=3","gravatar_id":"","url":"https://api.github.com/users/william-tran","html_url":"https://github.com/william-tran","followers_url":"https://api.github.com/users/william-tran/followers","following_url":"https://api.github.com/users/william-tran/following{/other_user}","gists_url":"https://api.github.com/users/william-tran/gists{/gist_id}","starred_url":"https://api.github.com/users/william-tran/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/william-tran/subscriptions","organizations_url":"https://api.github.com/users/william-tran/orgs","repos_url":"https://api.github.com/users/william-tran/repos","events_url":"https://api.github.com/users/william-tran/events{/privacy}","received_events_url":"https://api.github.com/users/william-tran/received_events","type":"User","site_admin":false},"created_at":"2016-08-23T18:20:20Z","updated_at":"2016-08-23T18:20:20Z","body":"On the client being used in RestTempalte vs Zuul, here's a conversation from the #spring-cloud Pivotal Slack channel on Aug 12\r\n> William Tran\r\nI’m trying to figure out how to get Ribbon retry to work with a `@LoadBalanced` RestTemplate\r\nBut I can’t seem to connect the dots to an instance of `com.netflix.client.RetryHandler`\r\n\r\n>Spencer Gibb [1:18 PM]  \r\nby default we don’t use the ribbon client (it doesn’t support patch for example), therefore it's retry doesn’t work by default.\r\n\r\n>William Tran [1:19 PM]  \r\nahh ok thanks. Is retry supported on SC-Zuul?\r\n\r\n>Spencer Gibb [1:21 PM]  \r\nin brixton restclient is still the default I think, so yes. In camden it is no longer the default. It should still retry though\r\n\r\nAbout the phases of blue-green, being able to manage all those phases would be ideal, but I'm really looking for support of the most basic slice, where an app instance goes down (planned or unplanned), and you want to fail over to other instances without service interruption. I guess this fail-over feature that I'm asking for isn't only useful for blue green deployments. "}}
{"actor":{"display_login":"william-tran"}}