Dropwizard ¡ A ¡RESTful ¡Love ¡Story ¡ ¡ Ryan ¡Kennedy ¡(@rckenned) ¡ Core ¡Services ¡@ ¡Yammer ¡
Dropwizard ¡ A ¡RESTful ¡Love ¡Story ¡ ¡ Ryan ¡Kennedy ¡(@rckenned) ¡ Core ¡Services ¡@ ¡Yammer ¡+ ¡MicrosoE ¡
What ¡on ¡earth ¡is ¡ Dropwizard? ¡
Some ¡bearded ¡jerk ¡in ¡ ¡ a ¡pointy ¡hat… ¡
or… ¡
Started ¡at ¡Yammer ¡as ¡three ¡services ¡ with ¡largely ¡copy/pasted ¡code ¡
By ¡service ¡number ¡three ¡we ¡ idenOfied ¡and ¡disOlled ¡the ¡paQern ¡
What ¡was ¡the ¡paQern? ¡
“Dropwizard ¡has ¡out-‑of-‑the-‑box ¡ support ¡for ¡sophisOcated ¡ configuraOon, ¡applicaOon ¡metrics, ¡ logging, ¡operaOonal ¡tools, ¡and ¡much ¡ more, ¡allowing ¡you ¡and ¡your ¡team ¡ to ¡ship ¡a ¡producOon-‑quality ¡HTTP +JSON ¡web ¡service ¡…” ¡
“Dropwizard ¡has ¡out-‑of-‑the-‑box ¡ support ¡for ¡sophisOcated ¡ configuraOon, ¡applicaOon ¡metrics, ¡ logging, ¡operaOonal ¡tools, ¡and ¡much ¡ more, ¡allowing ¡you ¡and ¡your ¡team ¡ to ¡ship ¡a ¡producOon-‑quality ¡HTTP +JSON ¡web ¡service ¡…” ¡
YAML ¡configuraOon ¡file ¡
hQp: ¡ ¡ ¡port: ¡8080 ¡ ¡ ¡adminPort: ¡8081 ¡ ¡ # ¡a ¡string ¡ foo: ¡foo ¡value ¡ ¡ # ¡a ¡duraOon ¡ bar: ¡60 ¡seconds ¡ ¡ # ¡a ¡number ¡ baz: ¡10101 ¡
ConfiguraOon ¡validaOon ¡
public ¡class ¡MyAppConfiguraOon ¡ ¡ ¡ ¡extends ¡ConfiguraOon ¡{ ¡ ¡ ¡@NotBlank ¡ ¡ ¡private ¡String ¡foo; ¡ ¡ ¡ ¡@NotNull ¡ ¡ ¡private ¡DuraOon ¡bar ¡= ¡DuraOon.minutes(10); ¡ ¡ ¡ ¡@Min(1) ¡ ¡ ¡@Max(1024) ¡ ¡ ¡private ¡long ¡baz ¡= ¡1; ¡ } ¡
“Dropwizard ¡has ¡out-‑of-‑the-‑box ¡ support ¡for ¡sophisOcated ¡ configuraOon, ¡applicaOon ¡metrics, ¡ logging, ¡operaOonal ¡tools, ¡and ¡much ¡ more, ¡allowing ¡you ¡and ¡your ¡team ¡ to ¡ship ¡a ¡producOon-‑quality ¡HTTP +JSON ¡web ¡service ¡…” ¡
Gauges ¡ Metrics.newGauge(My.class, ¡“jobs", ¡ ¡ ¡new ¡Gauge<Integer>() ¡{ ¡ ¡ ¡ ¡ ¡ ¡@Override ¡ ¡ ¡ ¡ ¡ ¡public ¡Integer ¡value() ¡{ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡return ¡queue.size(); ¡ ¡ ¡ ¡ ¡ ¡} ¡ ¡} ¡ ); ¡
Counters ¡ Counter ¡pendingJobs ¡= ¡Metrics.newCounter(My.class, ¡“jobs"); ¡ ¡ public ¡void ¡addJob(Job ¡job) ¡{ ¡ ¡ ¡ ¡ ¡pendingJobs.inc(); ¡ ¡ ¡ ¡ ¡queue.offer(job); ¡ } ¡ ¡ public ¡Job ¡takeJob() ¡{ ¡ ¡ ¡ ¡ ¡pendingJobs.dec(); ¡ ¡ ¡ ¡ ¡return ¡queue.take(); ¡ } ¡
Meters ¡ Meter ¡requests ¡= ¡Metrics.newMeter( ¡ ¡ ¡My.class, ¡"requests", ¡ ¡ ¡ ¡"requests", ¡TimeUnit.SECONDS); ¡ ¡ public ¡void ¡handleRequest(Request ¡request, ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡Response ¡response) ¡{ ¡ ¡ ¡ ¡ ¡requests.mark(); ¡ ¡ ¡ ¡ ¡// ¡etc ¡ } ¡
Histograms ¡ Histogram ¡responseSizes ¡= ¡Metrics.newHistogram( ¡ ¡ ¡My.class, ¡"response-‑sizes"); ¡ ¡ public ¡void ¡handleRequest(Request ¡request, ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡Response ¡response) ¡{ ¡ ¡ ¡ ¡ ¡// ¡etc ¡ ¡ ¡ ¡ ¡int ¡length ¡= ¡response.getContent().length; ¡ ¡ ¡ ¡ ¡responseSizes.update(length); ¡ } ¡
Timers ¡ Timer ¡responses ¡= ¡Metrics.newTimer(My.class, ¡"responses", ¡ ¡ ¡ ¡TimeUnit.MILLISECONDS, ¡TimeUnit.SECONDS); ¡ ¡ public ¡String ¡handleRequest(Request ¡request, ¡Response ¡response) ¡{ ¡ ¡ ¡ ¡ ¡final ¡TimerContext ¡context ¡= ¡responses.Ome(); ¡ ¡ ¡ ¡ ¡try ¡{ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡// ¡etc; ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡return ¡"OK"; ¡ ¡ ¡ ¡ ¡} ¡finally ¡{ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡context.stop(); ¡ ¡ ¡ ¡ ¡} ¡ } ¡
Health ¡Checks ¡ public ¡class ¡DatabaseHealthCheck ¡extends ¡HealthCheck ¡{ ¡ ¡ ¡ ¡ ¡@Override ¡ ¡ ¡ ¡ ¡public ¡Result ¡check() ¡throws ¡ExcepOon ¡{ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡if ¡(database.isConnected()) ¡{ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡return ¡Result.healthy(); ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡} ¡else ¡{ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡return ¡Result.unhealthy("Cannot ¡connect ¡to ¡db”); ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡} ¡ ¡ ¡ ¡ ¡} ¡ } ¡
“Dropwizard ¡has ¡out-‑of-‑the-‑box ¡ support ¡for ¡sophisOcated ¡ configuraOon, ¡applicaOon ¡metrics, ¡ logging, ¡operaOonal ¡tools, ¡and ¡much ¡ more, ¡allowing ¡you ¡and ¡your ¡team ¡ to ¡ship ¡a ¡producOon-‑quality ¡HTTP +JSON ¡web ¡service ¡…” ¡
JMX ¡ReporOng ¡
HTTP ¡ReporOng ¡
Metrics ¡ hQp://host:adminPort/metrics ¡
Metrics ¡reporters ¡can ¡be ¡added ¡to ¡ adapt ¡dropwizard ¡metrics ¡to ¡your ¡ collecOon ¡system ¡of ¡choice ¡
Health ¡Checks ¡ hQp://host:adminPort/healthcheck ¡
Thread ¡Dumps ¡ hQp://hostname:adminPort/threads ¡
Ping ¡ hQp://hostname:adminPort/ping ¡
“Dropwizard ¡has ¡out-‑of-‑the-‑box ¡ support ¡for ¡sophisOcated ¡ configuraOon, ¡applicaOon ¡metrics, ¡ logging, ¡operaOonal ¡tools, ¡and ¡much ¡ more, ¡allowing ¡you ¡and ¡your ¡team ¡ to ¡ship ¡a ¡producOon-‑quality ¡HTTP +JSON ¡web ¡service ¡…” ¡
Dropwizard ¡provides ¡its ¡own ¡ applicaOon ¡logging ¡abstracOon ¡
HTTP ¡request ¡logging ¡is ¡ supported ¡as ¡well ¡
Dropwizard ¡provides ¡log ¡file ¡ rotaOon ¡and ¡compression ¡
“Dropwizard ¡has ¡out-‑of-‑the-‑box ¡ support ¡for ¡sophisOcated ¡ configuraOon, ¡applicaOon ¡metrics, ¡ logging, ¡operaOonal ¡tools, ¡and ¡much ¡ more, ¡allowing ¡you ¡and ¡your ¡team ¡ to ¡ship ¡a ¡producOon-‑quality ¡HTTP +JSON ¡web ¡service ¡…” ¡
The ¡unbeatable ¡Jackson ¡
“Dropwizard ¡has ¡out-‑of-‑the-‑box ¡ support ¡for ¡sophisOcated ¡ configuraOon, ¡applicaOon ¡metrics, ¡ logging, ¡operaOonal ¡tools, ¡and ¡much ¡ more, ¡allowing ¡you ¡and ¡your ¡team ¡ to ¡ship ¡a ¡producOon-‑quality ¡HTTP +JSON ¡web ¡service ¡…” ¡
Dropwizard ¡embeds ¡JeQy ¡for ¡all ¡ your ¡HTTP ¡serving ¡needs ¡
JAX-‑RS ¡(JSR-‑311) ¡for ¡all ¡your ¡ RESTful ¡needs ¡
@Path(“/users/{id}”) ¡ public ¡class ¡UserResource ¡{ ¡ ¡ ¡ ¡ ¡@GET ¡ ¡ ¡ ¡ ¡public ¡User ¡get(@PathParam(“id”) ¡long ¡id) ¡{ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡return ¡db.findUserById(id); ¡ ¡ ¡ ¡ ¡} ¡ ¡ ¡ ¡ ¡ ¡@PUT ¡ ¡ ¡ ¡ ¡public ¡User ¡update(@PathParam(“id”) ¡long ¡id, ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡User ¡user) ¡{ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡return ¡db.updateUser(id, ¡user); ¡ ¡ ¡ ¡ ¡} ¡ } ¡
How ¡Yammer ¡uses ¡Dropwizard ¡
Lots ¡of ¡small ¡services…16 ¡and ¡ counOng ¡
Maven ¡is ¡our ¡friend ¡
SOck ¡the ¡code ¡in ¡GitHub ¡
Shade ¡your ¡JARs ¡
Get ¡yourself ¡some ¡conOnuous ¡ integraOon ¡
Write ¡yourself ¡a ¡startup ¡script ¡
Have ¡a ¡good ¡deploy ¡story ¡
Over ¡Ome, ¡Dropwizard ¡has ¡ grown ¡a ¡few ¡appendages ¡
Dropwizard ¡Client ¡ HQpClient ¡or ¡JerseyClient ¡flavors ¡
Dropwizard ¡DB ¡ JDBI ¡as ¡a ¡service ¡
Dropwizard ¡AuthenOcaOon ¡ Abstracted ¡authenOcaOon…providers ¡ for ¡OAuth ¡2 ¡and ¡Basic ¡Auth ¡
More recommend