Dropwizard and Friends

On a Twelve-factor Quest

Sydney MicroServices Meetup April 2015

About Me

  • Comp Science Bachelor UNSW
  • Applied Finance PostGrad at Macquarie Uni
  • ESB driver at Accenture, BGI/BlackRock, Macquarie Group
  • Now Microservicing Trunk Platform

yunspace

yunzhilin

yunspace.com

  • My opinions does not reflect the view of the company
  • Shout out if you have questions, or answers

Why
Demo

Decisions

CD + Docker

Why Dropwizard?

Standalone App

public static void main(String[] args) throws Exception {
    new LazyCatApplication().run(args);
}
java -jar build/awesome_api.jar server awesome_api.yml

No War Files, No App Servers

Builds and runs a Fat Jar

Start Application in a simple Main() method

Who Uses Dropwizard?

Surely Java without App Server is unstable?

Production Ready

  • Ops Friend
  • Health Checks
  • Metrix

More so than most Enterprise Apps

Plays Well with Others

Easy to do the Right Thing

Dropwizard makes it easy to do the right thing, allowing you to concentrate on the essential complexity of a problem rather than the plumbing

ThoughtWorks Technology Radar

We agree

High

Performance

techempower.com/benchmarks/

Low

Latency

techempower.com/benchmarks/

Compared to Rails

Dropping Rails for Dropwizard? - Yammer, April 2014

Compared Spring Boot

Compared to RatPack

public class FooBarFactory implements HandlerFactory {

  @Override
  public Handler create(LaunchConfig launchConfig) throws Exception {
    return Guice.builder(launchConfig)
      .bindings(bindingsSpec -> bindingsSpec.add(new MyModule()))
      .build(chain -> chain
        .handler("foo", context -> context.render("from the foo handler"))
        .handler("bar", context -> context.render("from the bar handler")));
    }
}
public class FooBarApplication extends Application<FooBarConfig> {
  
  public static void main(String[] args) throws Exception {
    new FooBarApplication().run(args);
  }
  
  @Override
  public void run(final FooBarApplication configuration, final Environment environment) throws Exception {
    environment.register(FooResource.class);
    environment.register(BarResrouce.class);
  }
}

@Path("/foo")
@Consumes(APPLICATION_JSON) @Produces(APPLICATION_JSON)
public class FooResource {
  @GET
  public String getFoo() {
    return "from the foo handler";
  }
}
  • Dropwizard is more opinionated and explicit

Right Tool for the Right Job

  • Not a silver bullet
  • We also use Rails to leverage neat Gems
  • And AngularJs on HarpJs for Static Sites

Build another "Hello World" App?

Demo

Let's build a Dropwizard Turbo app using LazyBones!

12 Factors

Design Decisions

Iron Fisted

Gradle

Declare and isolate Dependencies (II)

 

Portable "gradlew" is great for CI & locks gradle version

 

More than just Dependency Management:

  • builds shadow

Configuration

java \
  -Ddw.dataSource.driverClass=$DATABASE_DRIVER -Ddw.dataSource.url=$DATABASE_URL \
  -Ddw.dataSource.user=$DATABASE_USER -Ddw.dataSource.password=$DATABASE_PASSWORD \
  -jar build/application.jar server config.yml

1. Replace config.yml variables in run command (messy):

dataSource:
  driverClass: ${env.HIBERNATE_DRIVER!'org.h2.Driver'}
  user: ${env.HIBERNATE_USER!'sa'}
  password: ${env.HIBERNATE_PASSWORD!'sa'}
  url: ${env.HIBERNATE_URL!'jdbc:h2:./build/h2db'}

2. Use Dropwizard-Template-Config to add ${env} in config.yml: 

java -jar build/application.jar server config.yml

Modules

Swagger.IO

Integration using our own code

New Relic

Dockerfile

FROM errordeveloper/oracle-jre

ENV HOME /root/
WORKDIR /app/

# newrelic
RUN curl -L --silent --retry 3 \
    https://download.newrelic.com/newrelic/java-agent/newrelic-agent/current/newrelic-java.zip -o newrelic-java.zip
RUN unzip newrelic-java.zip && \
    rm newrelic/*.xml newrelic/*.xsd newrelic/*.yml newrelic/newrelic-api*.jar
ADD newrelic/newrelic.yml /app/newrelic/newrelic.yml

# plamasphere
ADD platmasphere-services.yml /app/
ENV PLATMA_VERSION latest
ADD build/platmasphere-services.jar /app/platmasphere-services.jar

# run
EXPOSE 9090
ENTRYPOINT [ "java" ]
CMD ["-javaagent:newrelic/newrelic.jar", "-jar", "platmasphere-services.jar", "server", "platmasphere-services.yml"]

Tips

  • Joda DateTime is NOT equivalent to JSR-310 LocalDateTime. Use ZonedDateTime or OffsetDateTime
compile "org.jadira.usertype:usertype.extended:3.2.0.GA"
  • Use Governator @LazySingleton if you have issue with Guice eager @Singleton
    compile("com.netflix.governator:governator:${governatorVersion}") {
        exclude group: 'com.google.guava', module: 'guava'
        exclude group: 'commons-lang'
    }
  • Multiple Database Schema Support: have a look here

Continuous Delivery

+

Docker

Snap-CI

Continuous Delivery enables:

Pact Contract 

{
  "description": "request for getting property 80 CLARENCE ST",
  "provider_state": "property 80 CLARENCE ST exists",
  "request": {
    "method": "get",
    "path": "/properties/1",
    "headers": {
      "Tenant": "trunk",
      "Authorization": "Bearer valid_token"
    }
  },
  "response": {
    "status": 200,
    "headers": {
      "Access-Control-Allow-Origin": "*",
      "Access-Control-Allow-Headers": "origin, content-type, accept, authorization, tenant",
      "Access-Control-Allow-Credentials": "true",
      "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS, HEAD",
      "Access-Control-Max-Age": "43200"
    },
    "body": {
      "id": 1,
      "addressLine": "80 CLARENCE ST",
      "postcode": "2000",
      "state": "NSW",
      "suburb": "SYDNEY",
      "streamId": 1
    }
  }
}

BinTray and Quay.io

Build Docker Images

Database Migration

Prior to deploying to a Environment, we run DB Migration as Once off Admin Processes (XII) 

./gradlew dbMigrate -Pdb_schema=
./gradlew dbTag -Pdb_schema=

Deploy Docker Container

Docker Containers takes care of:

Running Containers in Tutum

Questions

Made with Slides.com