Workshop Edition
Grails... microservices...
you must be crazy man!
1st Career
2nd Career
OCI Grails Team
Microservices are small, autonomous services that work together.
Sam Newman Building Microservices, O'Reilly Media
http://www.whattofix.com/images/ComplexERDExample.gif
Probably not small functional scope...
Everything should be made as simple as possible, but not simpler*
* though attributed to Einstein, this simple quote is actually from
Roger Sessions paraphrasing (and simplifying!) a statement by Albert Einstein
A system that is hard to understand is hard to change.
— Eric Evans, Domain-Driven Design
http://www.memes.com/meme/498049
http://bit.ly/thoughtworks-consumer-driven-contracts
http://famouswonders.com/wp-content/gallery/pyramids-of-egypt/pyramid-of-khafre.jpg
http://martinfowler.com/articles/microservices.html
http://www.openmakesoftware.com/images/ReleaseEngineer/CI-CD.png
https://media.licdn.com/mpr/mpr/p/8/005/083/1a8/257d716.jpg
http://kennysilva.net/wp-content/uploads/2010/12/orchestra-conductor.jpg
class Passenger {
String accountNo
String firstName
String lastName
Address billingAddress
Payment paymentPreference
List<Payment> paymentHistory
Phone home
Phone mobile
Phone work
BloodType bloodType
...
}
// For Trip Management
class Passenger {
String accountNo
String firstName
String lastName
Phone mobile
...
}
// For Billing
class Passenger {
String accountNo
String firstName
String lastName
Address billingAddress
List<Payment> paymentHistory
Phone home
Phone work
...
}
The evils of too much coupling between services are far worse than the problems caused by code duplication.
- Sam Newman, Building Microservices
"ELK Stack"
"They're inside the room!"
"Yikes!"
"Mmm, you look tasty."
Perimeter security reminds me of the movie, Aliens
Coming up:
Spring Boot & Spring Cloud to the rescue!
Managers: Developers more likely to join and stay where they can work on new stuff
There are many metrics out of the box, but you can create your own.
http://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-endpoints.html
http://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-endpoints.html
http://bit.ly/vignette2_wikia_nocookie_net_ghostbusters
http://martinfowler.com/bliki/CircuitBreaker.html
Full stack != monolith
Web UI, SQL / NOSQL Database Support, Spring, Hibernate, Security, REST, Java, Groovy...
$grails create-app HelloWorld
grails> create-controller demo.Hello
package demo
class HelloController {
def index() {
render 'Hello SpringOne2GX 2015!'
}
}
Full stack CRUD apps are about as easy...
1. Create controller
2. Make it do something
3. See it to believe it!
package demo
class Person {
String firstName
String lastName
String email
String twitterHandle
static constraints = {
firstName blank:false, maxSize: 32
lastName blank: false, maxSize: 64
email blank: false, maxSize: 128, email:true
twitterHandle nullable:true, maxSize:64
}
}
grails> run-app
package demo
import grails.rest.RestfulController
class PersonController extends RestfulController<Person> {
static responseFormats =['json', 'xml']
PersonController() {
super(Person)
}
def findPersonsWithLastNameLike(String likeness) {
respond Person.findByLastNameLike("${likeness}%")
}
}
class UrlMappings {
static mappings = {
"/persons"(resources:'person')
"/persons/search/withLastNameLike/$likeness"(controller: 'person',
action: 'findPersonsWithLastNameLike')
}
}
$ curl -i -X GET http://localhost:8080/persons.xml
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
X-Application-Context: application:development
Content-Type: text/xml;charset=UTF-8
Transfer-Encoding: chunked
Date: Mon, 07 Sep 2015 21:26:16 GMT
<?xml version="1.0" encoding="UTF-8"?><list />
$
200 OK good ... XML weird, but you wanted weird
$ curl -i -X GET http://localhost:8080/persons
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
X-Application-Context: application:development
Content-Type: text/xml;charset=UTF-8
Transfer-Encoding: chunked
Date: Mon, 07 Sep 2015 21:26:16 GMT
[]
$
200 OK good ... JSON good.
package demo
import grails.rest.Resource
@Resource(uri='/persons', formats=['json', 'xml'])
class Person {
String firstName
String lastName
String email
String twitterHandle
static constraints = {
firstName blank:false, maxSize: 32
lastName blank: false, maxSize: 64
email blank: false, maxSize: 128, email:true
twitterHandle nullable:true, maxSize:64
}
}
$ curl -i -X GET --header "Accept:application/json" http://localhost:8080/persons
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
X-Application-Context: application:development
Content-Type: text/xml;charset=UTF-8
Transfer-Encoding: chunked
Date: Mon, 07 Sep 2015 21:26:16 GMT
[]
$
200 OK good ... JSON good.
$ curl -i -X GET http://localhost:8080/persons.json
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
X-Application-Context: application:development
Content-Type: text/xml;charset=UTF-8
Transfer-Encoding: chunked
Date: Mon, 07 Sep 2015 21:26:16 GMT
[]
$
200 OK good ... JSON good.
package demo
import grails.rest.Resource
@Resource(uri='/persons')
class Person {
String firstName
String lastName
String email
String twitterHandle
static constraints = {
firstName blank:false, maxSize: 32
lastName blank: false, maxSize: 64
email blank: false, maxSize: 128, email:true
twitterHandle nullable:true, maxSize:64
}
}
grails create-app RestfulCrud
$ curl -i -X GET http://localhost:8080/persons
[jfrosch@localhost demo]$ HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
X-Application-Context: application:development
Content-Type: text/xml;charset=UTF-8
Transfer-Encoding: chunked
Date: Mon, 07 Sep 2015 21:26:16 GMT
<?xml version="1.0" encoding="UTF-8"?><list />
$
Hmm... 200 OK good ... XML bad.
Download all the sources for this from: https://github.com/jfrosch/GrailsMicroFederation
/product-catalog acts as the root of the uri
product-catalog is the name we map the Zuul route to
Can use @EnableDiscoveryClient if not intending to use Netflix implementation
Notice we're using Zuul server at port 8765 and Zuul route, not Recommendation Engine app's endpoint directly
I've had some difficulty applying circuit-breakers in controllers, so recommend doing so only in services
Note we're using Zuul server, not a microservice endpoint, to catch all data streams
All services are up
... After killing recommendation engine ...
... After restarting recommendation engine ...
You'd be crazy to adopt a microservice architecture using Grails...
unless your application needs to be ...
(even if your company isn't ready for the cloud yet)