Upload
andre-goliath
View
280
Download
2
Embed Size (px)
Citation preview
Das kannste schon so machen…
André Goliath
Disclaimer:This talk is bad
Because I had no timeBecause of the issues this talk is about
(makes sense, right?)
That being said…
Spring Boot & Netflix OSS StackWebServiceTemplate & Proxies
Jenkins & NPM
Spring Boot & Netflix OSS StackWebServiceTemplate & Proxies
Jenkins & NPM
You all know I´m a nice, calm, relaxed, chilled, error-forgiving
guy, right?
@ControllerAdvicepublic class GlobalControllerExceptionHandler extends ResponseEntityExceptionHandler { …
@ExceptionHandler({Exception.class}) private ResponseEntity<Object> handleAllUnknownExceptions(Exception ex) { return handleExceptionInternal(ex, null, null, HttpStatus.INTERNAL_SERVER_ERROR, null); }
@Override @ResponseBody protected ResponseEntity<Object> handleExceptionInternal(Exception ex, Object body, HttpHeaders headers, HttpStatus status, WebRequest request) {
BaseResponse errorMessage = createErrorMessage(ex); HttpStatus returnStatus = status != null ? status : HttpStatus.INTERNAL_SERVER_ERROR;
ResponseStatus exResponseStatus = AnnotationUtils.findAnnotation(ex.getClass(), ResponseStatus.class);
if (exResponseStatus != null) { returnStatus = exResponseStatus.value(); } return new ResponseEntity<>(errorMessage, headers, returnStatus); }
}
@Configuration@EnableWebMvcpublic class DispatcherServletConfigurer{
@Bean public FSLDispatcherServletHandlerErrorConfigurator getDispatcherServletPostProcessor(){ return new FSLDispatcherServletHandlerErrorConfigurator(); }
public class FSLDispatcherServletHandlerErrorConfigurator implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName) throws …{ if (bean instanceof DispatcherServlet) { DispatcherServlet disp = ((DispatcherServlet) bean); disp.setThrowExceptionIfNoHandlerFound(true); } return bean; }… }
That´s so Spring Boot 1.2.x!(1.2 was released in Dec 2014, 1.3 in Nov 2015)
spring.mvc.throw-exception-if-no-handler-found=true spring.resources.add-mappings=false
(you still need the @ControllerAdvice though)
NETFLIX OSS
ConfigserverSpring Cloud ConfigService Registry eurekaReverse Proxy zuulCircuit Breaker hystrix
Client
Reverse Proxy(ZUUL)
Service Registry(EUREKA) Config Server
So how do you deliver the configuration
for all your microservices and environments?
HINT: NOT IN ONE BIG ZIP FILE
C:\YOURSTUFF\CONFIG-BAD\\+---development| global.yml| service-a.yml| service-b.yml| service-c.yml| | +---production| global.yml| service-a.yml| service-b.yml| service-c.yml| \---uat global.yml service-a.yml service-b.yml service-c.yml
C:\YOURSTUFF\CONFIG-BAD\\+---development| global.yml| service-a.yml| service-b.yml| service-c.yml| | +---production| global.yml| service-a.yml| service-b.yml| service-c.yml| \---uat global.yml service-a.yml service-b.yml service-c.yml
C:\YOURSTUFF\CONFIG-GOOD\\|-- development.yml|-- production.yml|-- uat.yml| +---service-a| service-a-development.yml| service-a-production.yml| service-a-uat.yml| +---service-b| service-b-development.yml| service-b-production.yml| service-b-uat.yml| \---service-c service-c-development.yml service-c-production.yml service-c-uat.yml
C:\YOURSTUFF\CONFIG-BAD\\+---development| global.yml| service-a.yml| service-b.yml| service-c.yml| | +---production| global.yml| service-a.yml| service-b.yml| service-c.yml| \---uat global.yml service-a.yml service-b.yml service-c.yml
C:\YOURSTUFF\CONFIG-GOOD\\|-- development.yml|-- production.yml|-- uat.yml| +---service-a| service-a-development.yml| service-a-production.yml| service-a-uat.yml| +---service-b| service-b-development.yml| service-b-production.yml| service-b-uat.yml| \---service-c service-c-development.yml service-c-production.yml service-c-uat.yml
Never usedashes In
service names!
What is that zuul anyway?And what does it do?
AND HOW DO WE USE IT?
@SpringBootApplication@Controller@EnableZuulProxypublic class ZuulApplication {
public static void main(String[] args) { new SpringApplicationBuilder(ZuulApplication.class) .web(true).run(args); }}
ZUUL DOES MUCH MORE THINGS THEN WE SEE!
NOTE TO SELF:SPRING DOES NOT USE SEMANTIC
VERSIONING!
Lessons learnedfrom working with Spring
NEVER TRUST DEFAULT VALUES
READ THE FRIENDLY MANUAL…
… AND ESPECIALLYTHE RELEASE NOTES!
Spring Boot & Netflix OSS StackWebServiceTemplate & Proxies
Jenkins & NPM
private WebServiceTemplate attachProxy(WebServiceTemplate template) { if (config.getUseProxy()) { template.setProxy(new HttpHost(config.getProxyHost(), config.getProxyPort())) } return template; }}
private WebServiceTemplate attachProxy(WebServiceTemplate template) { if (config.getUseProxy()) { if (senderForProxy == null) { HttpClient client = HttpClients.custom() .setProxy(new HttpHost(config.getProxyHost(), config.getProxyPort())) .build(); senderForProxy = new HttpComponentsMessageSender(client); } template.setMessageSender(senderForProxy); } return template; }}
org.springframework.ws.client.WebServiceIOException: I/O error: null; nested exception is org.apache.http.client.ClientProtocolException
at org.springframework.ws.client.core.WebServiceTemplate.sendAndReceive(WebServiceTemplate.java:543)
...Caused by: org.apache.http.client.ClientProtocolException
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:909)
... 32 moreCaused by: org.apache.http.ProtocolException: Content-Length header already present
... 39 more
private WebServiceTemplate attachProxy(WebServiceTemplate template) { if (config.getUseProxy()) { if (senderForProxy == null) { HttpClient client = HttpClients.custom() .setProxy(new HttpHost(config.getProxyHost(), config.getProxyPort())) .addInterceptorFirst( new HttpComponentsMessageSender .RemoveSoapHeadersInterceptor() ) .build(); senderForProxy = new HttpComponentsMessageSender(client); } template.setMessageSender(senderForProxy); } return template; }}
SSL Protocol Error: Handshake failure
private WebServiceTemplate attachProxy(WebServiceTemplate template) { if (config.getUseProxy()) { if (senderForProxy == null) { HttpClient client = HttpClients.custom() .useSystemProperties() .setProxy(new HttpHost(config.getProxyHost(), config.getProxyPort())) .addInterceptorFirst( new HttpComponentsMessageSender .RemoveSoapHeadersInterceptor() ) .build(); senderForProxy = new HttpComponentsMessageSender(client); } template.setMessageSender(senderForProxy); } return template; }}
400(a.k.a. „Bad Request“)
400(a.k.a. least helpful HTTP
response code of all times.)
…5 Hours of HTTP traffic comparison later…
SOAP-Namespaces?
Am I missing any HTTP header?Malformed XML?
No Proxy allowed? Still SSL issues?
…5 Hours of HTTP traffic comparison later…
Am I missing any HTTP header?
I am sending one header too much.
Am I missing any HTTP header?
private WebServiceTemplate attachProxy(WebServiceTemplate template) { if (config.getUseProxy()) { if (senderForProxy == null) { HttpClient client = HttpClients.custom() .useSystemProperties() .setProxy(new HttpHost(config.getProxyHost(), config.getProxyPort())) .addInterceptorFirst( new HttpComponentsMessageSender .RemoveSoapHeadersInterceptor() ) .build(); senderForProxy = new HttpComponentsMessageSender(client); senderForProxy.setAcceptGzipEncoding(false); } template.setMessageSender(senderForProxy); } return template; }}
It took me about 5 full days to get this right.
Lessons learnedfrom the proxy disaster
Have the samecommunication infrastructure
on every(!) test setup
No Proxy? Make your own.var http = require('http'), httpProxy = require('http-proxy');
var proxy = httpProxy.createProxyServer({});
var interceptingServer = http.createServer(function (req, res) { // define your custom logic to handle the request // and then proxy the request. proxy.web(req, res, {target: 'http://MyActualTargetService.com'});});
console.log("proxy listening on port 5050")interceptingServer.listen(5050);
https://github.com/nodejitsu/node-http-proxy
Talking about JavaScript…
Spring Boot & Netflix OSS StackWebServiceTemplate & Proxies
Jenkins & NPM
Node Package Manager v2is bad. Like, really bad.
So what’s the big deal?
npm install
…on Senacor Hardware: 15 min…on Clients Dev. Machine: 20 min…on Jenkins:. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Filesystem Size Used Avail Use% Mounted on.../dev/mapper/datavg-lv_optsoftware 492G 22G 446G 5% /opt/software
Filesystem Size Used Avail Use% Mounted on.../dev/mapper/datavg-lv_optsoftware 492G 22G 446G 5% /opt/software
Filesystem Inodes IUsed IFree IUse% Mounted on.../dev/mapper/datavg-lv_optsoftware 32768000 32428987 39013 99% /opt/software
Filesystem Size Used Avail Use% Mounted on.../dev/mapper/datavg-lv_optsoftware 492G 22G 446G 5% /opt/software
Filesystem Inodes IUsed IFree IUse% Mounted on.../dev/mapper/datavg-lv_optsoftware 32768000 32428987 39013 99% /opt/software
I lost track when the deepest node_modules pathwas about 2000 chars long…
npm dedupe would help,but only if npm install worked at least once…
Beware:Npm3 will be the default packagemanager starting with nodejs 5.x,and is a breaking change:
Lessons learned:We started the project when NodeJS 4.x and npm 3.xwere still unstable.That time is gone. Go for it.
Thank You!
André GoliathSenior Technical [email protected]