Microservice Decorator
coordinare i microservizi in modo semplice e dichiarativo
Tommaso Allevi
@allevo
Platform R&D Leader @ Mia-Platform
Perchè sviluppare a microservizi?
Disaccoppia componenti del progetto
Ogni microservizio può essere sviluppato con un suo linguaggio
Aiuta a dividere il problema in sottoproblemi
Scala i tuoi microservizi in modo indipendente
Riutilizzare i microservizi
è possibile testare la singola business logic
Sviluppo incrementale di feature
Riutilizzare i microservizi
Sviluppo incrementale di feature
Dipendenze forti tra microservizi
Open/closed principle
Un'entità software dovrebbe essere aperta alle estensioni, ma chiusa alle modifiche.
Wikipedia
Esiste un modo per estendere senza modificare?
Microservice Decorator
Business Logic
API
Decoratore pre1
Decoratore pre2
Decoratore pre3
...
Decoratore post1
Decoratore post2
Decoratore post3
...
Flow
Un decoratore è
un componente dell'architettura
che può:
- Ricevere una notifica di quando c'è una richiesta/risposta
- Modificare la richiesta/risposta aggiungendo/togliendo parametri (querystring, header, body...)
- Fermare la richiesta stabilendo la risposta definitiva da dare al client (per esempio un check andato male)
Una possibile implementazione può essere fatta usando il protocollo HTTP nel quale il decoratore accetta in input la richiesta/risposta e risponde in base all'azione che deve essere compiuta
GET /incoming_url?foo=bar
pre1
pre2
business-service
GET /proxied-url?bar=foo
post3
{
"routes": {
"/incoming_url": {
"GET": {
"pre": [ "pre1", "pre2" ],
"call": "http://business-service/proxied-url",
"post": [ "post1" ]
}
},
},
"decorators": {
"pre1": {
"call": "http://some-service2/decorators/path1",
},
"pre2": {
"call": "http://other-service/decorators/path2",
},
"post1": {
"call": "http://some-service3/decorators/path3",
}
}
}
Il Microservice Decorator impone un interfaccia HTTP che ogni decoratore deve implementare
Un microservizio NON sono le API che espone
ma la business logic che implementa
È una limitazione?
No
Ports and Adapter Pattern
Esempio #1
Login
auth-service
session-manager
{
"routes": {
"/login": {
"POST": {
"pre": [ ],
"call": "http://auth-service/identify",
"post": [ "createSession" ]
}
}
},
"decorators": {
"createSession": {
"call": "http://session-manager/decorators/createSession",
}
}
}
Microservice Decorator
Auth
Service
Session
Manager
POST /login
Microservice
Decorator
POST /identify
POST
/decorators/createSession
POST /login
{ username: "aa", password: "bb" }
---> { userId: "1234" }
POST /decorators/createSession
{ userId: "1234" }
---> Set-Cookie: sid="abcd"
---> { userId: "1234" }
POST /identify
{ username: "aa", password: "bb" }
---> Set-Cookie: sid="abcd"
---> { userId: "1234" }
Esempio #2
Login con CSRF
Microservice Decorator
Auth
Service
Session
Manager
Microservice
Decorator
CSRF
Service
1
2
3
{
"routes": {
"/login": {
"POST": {
"pre": [ "checkCSRF" ],
"call": "http://auth-service/identify",
"post": [ "createSession" ]
}
}
},
"decorators": {
"createSession": {
"call": "http://session-manager/decorators/createSession",
},
"checkCSRF": {
"call": "http://csrf-service/decorators/checkCSRF",
}
}
}
Nessuna linea di codice esistente è stata modificata!
Abbiamo aggiunto le linee di codice necessarie per la nuova feature in un microservizio separato e modificato un file di configurazione
Esempio #3
Registrazione
{
"/signup": {
"POST": {
"pre": [ ],
"call": "http://auth-service/signup",
"post": [ ]
}
},
"decorators": {
}
}
Se volessimo aggiungere il controllo per il CSRF token?
{
"routes": {
"/signup": {
"POST": {
"pre": [ "checkCSRF" ],
"call": "http://auth-service/signup",
"post": [ ]
}
}
},
"decorators": {
"createSession": {
"call": "http://session-manager/decorators/createSession",
}
}
}
Se volessimo che l'utente sia già
loggato dopo la registrazione?
{
"routes": {
"/signup": {
"POST": {
"pre": [ "checkCSRF" ],
"call": "http://auth-service/signup",
"post": [ "createSession" ]
}
}
},
"decorators": {
"createSession": {
"call": "http://session-manager/decorators/createSession",
},
"checkCSRF": {
"call": "http://csrf-service/decorators/checkCSRF",
}
}
}
E la mail di benvenuto?
{
"routes": {
"/signup": {
"POST": {
"pre": [ "checkCSRF" ],
"call": "http://auth-service/signup",
"post": [ "createSession", "sendWelcomeMail" ]
}
}
},
"decorators": {
...
"sendWelcomeMail": {
"call": "http://mail-service/decorators/welcome"
}
}
}
Aggiungi comportamenti senza modificare i tuoi microservizi
- Tieni la business logic separata da side effects
- Aggiungi incrementalmente feature senza modificare il codice esistente
- Descrivi la tua architettura attraverso un unico file di configurazione
Esempio #4
Integrazione con un servizio Legacy
Requisiti
- la login Legacy deve continuare a funzionare senza interruzioni
- i nuovi servizi sono microservizi e il loro metodo di autenticazione è diverso da quello Legacy
- i nuovi servizi non accedono al database delle sessioni Legacy
- tra i nuovi servizi c'è un authentication service e un session manager
- i clients hanno una gestione dei cookie coerente (come un browser)
- tutti i servizi (nuovi e Legacy) sono servizi HTTP
Supponiamo di avere un "bel" monolita che per anni ha fatto il proprio lavoro bene e ora vorremmo accostare nuovi servizi a contorno che hanno un metodo di autenticazione diverso
Authentication Service
Session Manager
Credenziali => userId
userId => sessione (cookie, jwt...)
sessione (cookie, jwt...) => userId
Legacy service
POST /login: Credenziali => userId
GET /me: cookie => userId
Legacy
POST /login
SM
POST /login
{ ... }
+
sid cookie
GET /me
{ userId }
post decorator
{ ... }
+
sid cookie
+
sid2 cookie
{
"routes": {
"/login": {
"POST": {
"pre": [ ],
"call": "http://legacy/login",
"post": [ "createNewSession" ]
}
}
},
"decorators": {
"createNewSession": { "call": "http://session-manager/decorators/createSession" }
}
}
Possiamo aggiungere altri decoratori per ampliare le features implementate
CSRF token!
Route /login - Method POST
+-------------------+ +-----------------------+
| | | |
request ----------> checkCSRF +---------> Legacy ----------> createNewSession +---------> response
| | | |
+---------^---------+ +-----------^-----------+
| |
| |
v v
csrf-service session-manager
/decorators/checkCSRF /decorators/createNewSession
E la documentazione?
La configurazione del Microservice Decorator è già documentazione!
E per gli amanti dell'ASCII art:
{
"routes": {
"/orders/": {
"POST": {
"pre": [ "checkDishesAvailability", "checkAddress" ],
"call": "http://order-service/orders/",
"post": [ "makePayment", "markTheOrderAsPaid", "notifyTheUser", "notifyTheDeliveryBoy" ]
}
}
},
"decorators": {
"checkDishesAvailability": { "call": "http://dish-service/decorators/checkAvailability" },
"checkAddress": { "call": "http://address-service/decorators/checkAddress" },
"makePayment": { "call": "http://payment-service/decorators/payForTheOrder" },
"markTheOrderAsPaid": { "call": "http://order-service/decorators/markAsPaid" },
"notifyTheUser": { "call": "http://email-service/decorators/sendOrderMail" },
"notifyTheDeliveryBoy": { "call": "http://push-service/decorators/sendPushToDeliveryBoy" }
}
}
è un flusso di un ordine!
Quale flusso implementa questa configurazione?
Grazie!
(we are hiring!)
tommaso.allevi@mia-platform.eu
Microservice Decorator - Crafted Software
By Tommaso Allevi
Microservice Decorator - Crafted Software
- 560