Das kannste schon so
machen…
André Goliath
Disclaimer:
This talk is bad
Because I had no time
Because of the issues this talk is about
(makes sense, right?)
That being said…
Spring Boot & Netflix OSS Stack
WebServiceTemplate & Proxies
Jenkins & NPM
Spring Boot & Netflix OSS Stack
WebServiceTemplate & Proxies
Jenkins & NPM
You all know I´m a nice, calm, relaxed,
chilled, error-forgiving guy, right?
@ControllerAdvice
public 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
@EnableWebMvc
public 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
Configserver Spring Cloud Config
Service Registry eureka
Reverse Proxy zuul
Circuit 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:YOURSTUFFCONFIG-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:YOURSTUFFCONFIG-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:YOURSTUFFCONFIG-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:YOURSTUFFCONFIG-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:YOURSTUFFCONFIG-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 use
dashes In
service names!
What is that zuul anyway?
And what does it do?
AND HOW DO WE USE IT?
@SpringBootApplication
@Controller
@EnableZuulProxy
public 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 learned
from working with Spring
NEVER TRUST DEFAULT VALUES
READ THE FRIENDLY MANUAL…
… AND ESPECIALLY
THE RELEASE NOTES!
Spring Boot & Netflix OSS Stack
WebServiceTemplate & 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 more
Caused 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 learned
from the proxy disaster
Have the same
communication 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 Stack
WebServiceTemplate & Proxies
Jenkins & NPM
Node Package Manager v2
is 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 path
was about 2000 chars long…
npm dedupe would help,
but only if npm install worked
at least once…
Beware:
Npm3 will be the default package
manager starting with nodejs 5.x,
and is a breaking change:
Lessons learned:
We started the project when
NodeJS 4.x and npm 3.x
were still unstable.
That time is gone. Go for it.
Thank You!
André Goliath
Senior Technical Consultant
andre.goliath@senacor.de

Das kannste schon so machen

  • 1.
    Das kannste schonso machen… André Goliath
  • 2.
    Disclaimer: This talk isbad Because I had no time Because of the issues this talk is about
  • 3.
  • 4.
  • 6.
    Spring Boot &Netflix OSS Stack WebServiceTemplate & Proxies Jenkins & NPM
  • 7.
    Spring Boot &Netflix OSS Stack WebServiceTemplate & Proxies Jenkins & NPM
  • 8.
    You all knowI´m a nice, calm, relaxed, chilled, error-forgiving guy, right?
  • 10.
    @ControllerAdvice public class GlobalControllerExceptionHandlerextends 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); } }
  • 11.
    @Configuration @EnableWebMvc public class DispatcherServletConfigurer{ @Bean publicFSLDispatcherServletHandlerErrorConfigurator 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; } … }
  • 12.
    That´s so SpringBoot 1.2.x! (1.2 was released in Dec 2014, 1.3 in Nov 2015)
  • 13.
  • 14.
  • 15.
    Configserver Spring CloudConfig Service Registry eureka Reverse Proxy zuul Circuit Breaker hystrix
  • 16.
  • 17.
    So how doyou deliver the configuration for all your microservices and environments?
  • 18.
    HINT: NOT INONE BIG ZIP FILE
  • 19.
    C:YOURSTUFFCONFIG-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
  • 20.
    C:YOURSTUFFCONFIG-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:YOURSTUFFCONFIG-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
  • 21.
    C:YOURSTUFFCONFIG-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:YOURSTUFFCONFIG-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 use dashes In service names!
  • 22.
    What is thatzuul anyway? And what does it do? AND HOW DO WE USE IT?
  • 23.
    @SpringBootApplication @Controller @EnableZuulProxy public class ZuulApplication{ public static void main(String[] args) { new SpringApplicationBuilder(ZuulApplication.class) .web(true).run(args); } }
  • 24.
    ZUUL DOES MUCHMORE THINGS THEN WE SEE!
  • 26.
    NOTE TO SELF: SPRINGDOES NOT USE SEMANTIC VERSIONING!
  • 29.
  • 30.
  • 31.
  • 32.
    … AND ESPECIALLY THERELEASE NOTES!
  • 33.
    Spring Boot &Netflix OSS Stack WebServiceTemplate & Proxies Jenkins & NPM
  • 34.
    private WebServiceTemplate attachProxy(WebServiceTemplatetemplate) { if (config.getUseProxy()) { template.setProxy(new HttpHost(config.getProxyHost(), config.getProxyPort())) } return template; } }
  • 35.
    private WebServiceTemplate attachProxy(WebServiceTemplatetemplate) { 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; } }
  • 36.
    org.springframework.ws.client.WebServiceIOException: I/O error: null; nestedexception 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 more Caused by: org.apache.http.ProtocolException: Content-Length header already present ... 39 more
  • 38.
    private WebServiceTemplate attachProxy(WebServiceTemplatetemplate) { 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; } }
  • 39.
    SSL Protocol Error:Handshake failure
  • 41.
    private WebServiceTemplate attachProxy(WebServiceTemplatetemplate) { 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; } }
  • 43.
  • 44.
    400 (a.k.a. least helpfulHTTP response code of all times.)
  • 45.
    …5 Hours ofHTTP traffic comparison later… SOAP-Namespaces? Am I missing any HTTP header? Malformed XML? No Proxy allowed? Still SSL issues?
  • 46.
    …5 Hours ofHTTP traffic comparison later… Am I missing any HTTP header?
  • 48.
    I am sendingone header too much. Am I missing any HTTP header?
  • 49.
    private WebServiceTemplate attachProxy(WebServiceTemplatetemplate) { 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; } }
  • 50.
    It took meabout 5 full days to get this right.
  • 51.
  • 52.
    Have the same communicationinfrastructure on every(!) test setup
  • 53.
    No Proxy? Makeyour 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
  • 54.
  • 55.
    Spring Boot &Netflix OSS Stack WebServiceTemplate & Proxies Jenkins & NPM
  • 57.
    Node Package Managerv2 is bad. Like, really bad.
  • 61.
    So what’s thebig deal?
  • 62.
    npm install …on SenacorHardware: 15 min …on Clients Dev. Machine: 20 min …on Jenkins: . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
  • 63.
    Filesystem Size UsedAvail Use% Mounted on ... /dev/mapper/datavg-lv_optsoftware 492G 22G 446G 5% /opt/software
  • 64.
    Filesystem Size UsedAvail 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
  • 65.
    Filesystem Size UsedAvail 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 path was about 2000 chars long…
  • 66.
    npm dedupe wouldhelp, but only if npm install worked at least once…
  • 67.
    Beware: Npm3 will bethe default package manager starting with nodejs 5.x, and is a breaking change:
  • 68.
    Lessons learned: We startedthe project when NodeJS 4.x and npm 3.x were still unstable. That time is gone. Go for it.
  • 69.
    Thank You! André Goliath SeniorTechnical Consultant andre.goliath@senacor.de