SlideShare une entreprise Scribd logo
1  sur  77
Télécharger pour lire hors ligne
Building real-time web
apps using WEBSOcKeTS
WITH PLAY!
andrew@42go.com
@connerdelights
How we
used to
do it
request
How we
used to
do it
request
response
How we
used to
do it
request
response
new message!
How we
used to
do it
request
response
new message!
The web has
changed
(quite a bit)
The dynamic web
needs real-time
communication
The dynamic web
needs real-time
communication
short polling
short polling
short polling
short polling
Resource intensive,slow, limited toone response
Chunked Responses
Chunked Responses
Hacky,
no error handling,half-duplex
Long Polling
Long Polling
Long Polling
Long Polling
well supported,still half-duplex,single req/resp
These do not handle high
bursts of messages
These do not handle high
bursts of messages
Stuck with the single
request → response
model
GET / HTTP/1.1
Host: www.google.com
Connection: keep-alive
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/
28.0.1500.71 Safari/537.36
DNT: 1
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Cookie: PREF=ID=e248d326d84eb3dc:FF=0:TM=1372622071:LM=1274622070:S=2bERIaHgSKRjWeC8; NID=47=CHAZZVkq40TcovIu-
FuXlU0pF2UPfqqSEhNqx8hqUKnZ7-s4uxGjtBEFK7kRtTSVEu4fzJ00vhB4OrLRxw8JfV5EuiKczEC2_EHkBqr1kNwn_NdZ73XRl2umFybXYoiVD_
HTTP/1.1 200 OK
Date: Tue, 23 Jul 2013 23:28:02 GMT
Expires: -1
Cache-Control: private, max-age=0
Content-Type: text/html; charset=UTF-8
Set-Cookie: PREF=ID=e248d326d84eb3dc:FF=1997f24999d1d9ef:FF=0:TM=1334622374:LM=1374622082:S=ynynJppwL64C6VMRU;
expires=Thu, 23-Jul-2015 23:28:02 GMT; path=/; domain=.google.com
Content-Encoding: gzip
Server: gws
X-XSS-Protection: 1; mode=block
X-Frame-Options: SAMEORIGIN
Transfer-Encoding: chunked
Inefficient
Over 1kb in headers
Can
Play! do
these?
Can
Play! do
these?
Yes!
Can
Play! do
these?
In fact, if
you’re
supporting
older
browsers,
consider
them!
Yes!
Websockets
Websockets
Full duplex,efficient, fast,only newer* browsers
How fast are
websockets?
our office
EC2
US West
How fast are
websockets?
our office
EC2
US West
Average 10ms ping
~13ms mean improvement
Full benchmarks:
http://eng.42go.com/
GET / HTTP/1.1
Host: www.google.com
Connection: keep-alive
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/
28.0.1500.71 Safari/537.36
DNT: 1
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Cookie: PREF=ID=e248d326d84eb3dc:FF=0:TM=1372622071:LM=1274622070:S=2bERIaHgSKRjWeC8; NID=47=CHAZZVkq40TcovIu-
FuXlU0pF2UPfqqSEhNqx8hqUKnZ7-s4uxGjtBEFK7kRtTSVEu4fzJ00vhB4OrLRxw8JfV5EuiKczEC2_EHkBqr1kNwn_NdZ73XRl2umFybXYoiVD_
HTTP/1.1 200 OK
Date: Tue, 23 Jul 2013 23:28:02 GMT
Expires: -1
Cache-Control: private, max-age=0
Content-Type: text/html; charset=UTF-8
Set-Cookie: PREF=ID=e248d326d84eb3dc:FF=1997f24999d1d9ef:FF=0:TM=1334622374:LM=1374622082:S=ynynJppwL64C6VMRU;
expires=Thu, 23-Jul-2015 23:28:02 GMT; path=/; domain=.google.com
Content-Encoding: gzip
Server: gws
X-XSS-Protection: 1; mode=block
X-Frame-Options: SAMEORIGIN
Transfer-Encoding: chunked
Over 1kb in headers
How fast are
websockets?
Initial Websocket
transmission
Websocket
Client
HTTP
Client
How fast are
websockets?
EC2
US West
TCP Websocket
0.002ms 0.02ms
Websockets are
not magical :)
Full benchmarks:
http://eng.42go.com/
How fast are
websockets?
EC2
US West
TCP Websocket
0.002ms 0.02ms
Still quite fast
Full benchmarks:
http://eng.42go.com/
Websockets
deal with
streams of data
from the client
to the client
What are my messages?
Here’s Your messages!
You have a new notification
from the client
to the client
What are my messages?
Here’s Your messages!
You have a new notification
I visited my user profile page
I visited the home page
from the client
to the client
What are my messages?
Here’s Your messages!
You have a new notification
I visited my user profile page
I visited the home page
Here’s a Message for Frank
Got your message
from the client
to the client
What are my messages?
Here’s Your messages!
You have a new notification
I visited my user profile page
I visited the home page
Here’s a Message for Frank
Got your message
Code push, reconnect please!
from the client
to the client
How does
Play! handle
websockets?
How does
Play! handle
websockets?
let’s step back a bit...
val it = Seq(1,2,3,4,5).toIterator
while(it.hasNext) {
println(it.next())
}
Iterators
val it = Seq(1,2,3,4,5).toIterator
while(it.hasNext) {
println(it.next())
}
val list = Seq(1,2,3,4,5)
list.foreach(println)
Iterators
val list = Seq(1,2,3,4,5)
list.foreach(println)
Instead of imperatively traversing containers,
apply a function to elements in a container.
Iterators
val list = Seq(1,2,3,4,5)
list.foreach(println)
Container Function
Iterators
Iterators
val list = Seq(1,2,3,4,5)
list.foreach(println)
Container Function
Producer Consumer
Iteratee
(ie, the consumer)
Immutably consumes chunks from a Producer.
Think: Iterates over a stream*.
Iteratee
(ie, the consumer)
Immutably consumes chunks from a Producer.
Think: Iterates over a stream*.
Iteratees can actually do a bit more,
but we’ll save that for another day.
Enumerator
(ie, the PRODUCER)
Produces typed chunks.
Only produces when there is a CONSUMER.
Play! needs a producer and
consumer for a Websocket stream
val in = Iteratee.foreach[JsArray](println)
val in = Iteratee.foreach[JsArray](println)
Consumer
This iteratee will consume from an Enumerator
(the client), printing the input to the console
val in = Iteratee.foreach[JsArray](println)
val out = Enumerator("You connected!").andThen(Enumerator.eof)
Producer
This Enumerator will be consumed by an iteratee
(The client), sending a string then EOF
def index = WebSocket.using[JsArray] { request =>
val in = Iteratee.foreach[JsArray](println)
val out = Enumerator("You connected!").andThen(Enumerator.eof)
(in, out)
}
def index = WebSocket.using[JsArray] { request =>
val in = Iteratee.foreach[JsArray](println)
val out = Enumerator("You connected!").andThen(Enumerator.eof)
(in, out)
}
It works!
> var createSocket = function() {
var s = new WebSocket("ws://localhost:9000");
s.onopen = function() { s.send("['hey!']"); }
s.onclose = function(e) { console.log("closed!",e); }
s.onmessage = function(msg) { console.log("got: ", msg.data); }
return s;
}
undefined
> var socket = createSocket()
undefined
got: You connected!
closed!
CloseEvent {reason: "", code: 1005, wasClean: true, clipboardData:
def echo = WebSocket.using[JsArray] { request =>
val (out, channel) = Concurrent.broadcast[JsArray]
val in = Iteratee.foreach[JsArray](channel.push)
(in, out)
}
def echo = WebSocket.using[JsArray] { request =>
val (out, channel) = Concurrent.broadcast[JsArray]
val in = Iteratee.foreach[JsArray](channel.push)
(in, out)
}
feeds into
Channels let us
imperatively push data
into an enumerator
Channels
Channels...
how about a chat room?
super simple
^
Simplified version of the Play! Chat room
websocket sample
https://github.com/playframework/playframework/blob/master/samples/scala/websocket-chat
case class Join(username: String)
case class Quit(username: String)
case class Talk(username: String, text: String)
class ChatRoom extends Actor {
var members = Set.empty[String]
val (chatEnumerator, chatChannel) = Concurrent.broadcast[JsValue]
val chatBot = "Marvin"
 
def receive = ???
 
}
case class Join(username: String)
case class Quit(username: String)
case class Talk(username: String, text: String)
class ChatRoom extends Actor {
var members = Set.empty[String]
val (chatEnumerator, chatChannel) = Concurrent.broadcast[JsValue]
val chatBot = "Marvin"
 
def receive = ???
 
} channel
output
lets us push data
into the enumerator
case class Join(username: String)
case class Quit(username: String)
case class Talk(username: String, text: String)
class ChatRoom extends Actor {
var members = Set.empty[String]
val (chatEnumerator, chatChannel) = Concurrent.broadcast[JsValue]
val chatBot = "Marvin"
 
def receive = {
case Join(username) => {
members = members + username
broadcastMessage(chatBot, s"$username has joined")
sender ! chatEnumerator
}
case Quit(username) =>
case Talk(username, text) =>
}
 
def broadcastMessage(user: String, text: String): Unit = ???
}
case class Join(username: String)
case class Quit(username: String)
case class Talk(username: String, text: String)
class ChatRoom extends Actor {
var members = Set.empty[String]
val (chatEnumerator, chatChannel) = Concurrent.broadcast[JsValue]
val chatBot = "Marvin"
 
def receive = {
case Join(username) => {
members = members + username
broadcastMessage(chatBot, s"$username has joined")
sender ! chatEnumerator
}
case Quit(username) =>
case Talk(username, text) =>
}
 
def broadcastMessage(user: String, text: String): Unit = ???
}
send back a reference
to the chatroom’s enumerator
case class Join(username: String)
case class Quit(username: String)
case class Talk(username: String, text: String)
class ChatRoom extends Actor {
var members = Set.empty[String]
val (chatEnumerator, chatChannel) = Concurrent.broadcast[JsValue]
val chatBot = "Marvin"
 
def receive = {
case Join(username) => {
members = members + username
broadcastMessage(chatBot, s"$username has joined")
sender ! chatEnumerator
}
case Quit(username) => {
broadcastMessage(chatBot, s"$username has left")
members = members - username
}
case Talk(username, text) => broadcastMessage(username, text)
}
 
def broadcastMessage(user: String, text: String): Unit = ???
}
case class Join(username: String)
case class Quit(username: String)
case class Talk(username: String, text: String)
class ChatRoom extends Actor {
...
 
def broadcastMessage(user: String, text: String): Unit = {
val msg = Json.obj("user" -> JsString(user),
"message" -> JsString(text),
"members" -> JsArray(members.toList.map(JsString)))
chatChannel.push(msg)
}
}
object Application extends Controller {
lazy val chatroomActor = Akka.system.actorOf(Props[ChatRoom])
 
def chat(username: String) = WebSocket.async[JsValue] { request =>
(chatroomActor ? Join(username)) map {
// grab the Enumerator from ChatRoom:
case out: Enumerator[JsValue] =>
val in = Iteratee.foreach[JsValue] { event =>
chatroomActor ! Talk(username, (event  "text").as[String])
}.mapDone { _ =>
chatroomActor ! Quit(username)
}
(in, out)
}
}
}
This can be modified
to be a lightweight
pub-sub system by
creating many
channels
Play!
Lessons learned
use debugging tools!
Lessons learned
use debugging tools!
Lessons learned
weird things can happen when you’re
depending on a long-lived socket
Lessons learned
weird things can happen when you’re
depending on a long-lived socket
clients lie voodoo when
packet loss is high
disconnects
happen
Lessons learned
babysit connections in your application
ping / pong
Lessons learned
your clients need to auto-reconnect
(we’ll be open sourcing our
reconnecting WS library soon!)
Lessons learned
be careful about thread safety
val in = Iteratee.foreach[JsArray](/* handler */)
Lessons learned
make sure this guy is fast
val in = Iteratee.foreach[JsArray](/* handler */)
http://caniuse.com/websockets
http://caniuse.com/websockets
Find me:
andrew@42go.com
@connerdelights
Questions?
http://eng.42go.com/

Contenu connexe

Tendances

HTML5 vs Silverlight
HTML5 vs SilverlightHTML5 vs Silverlight
HTML5 vs SilverlightMatt Casto
 
Handling 10k requests per second with Symfony and Varnish - SymfonyCon Berlin...
Handling 10k requests per second with Symfony and Varnish - SymfonyCon Berlin...Handling 10k requests per second with Symfony and Varnish - SymfonyCon Berlin...
Handling 10k requests per second with Symfony and Varnish - SymfonyCon Berlin...Alexander Lisachenko
 
Real time web (Orbited) at BCNE3
Real time web (Orbited) at BCNE3Real time web (Orbited) at BCNE3
Real time web (Orbited) at BCNE3Alex Kavanagh
 
Implementing Comet using PHP
Implementing Comet using PHPImplementing Comet using PHP
Implementing Comet using PHPKing Foo
 
Solving anything in VCL
Solving anything in VCLSolving anything in VCL
Solving anything in VCLFastly
 
Websockets on the JVM: Atmosphere to the rescue!
Websockets on the JVM: Atmosphere to the rescue!Websockets on the JVM: Atmosphere to the rescue!
Websockets on the JVM: Atmosphere to the rescue!jfarcand
 
A language for the Internet: Why JavaScript and Node.js is right for Internet...
A language for the Internet: Why JavaScript and Node.js is right for Internet...A language for the Internet: Why JavaScript and Node.js is right for Internet...
A language for the Internet: Why JavaScript and Node.js is right for Internet...Tom Croucher
 
GWT Web Socket and data serialization
GWT Web Socket and data serializationGWT Web Socket and data serialization
GWT Web Socket and data serializationGWTcon
 
Reverse ajax in 2014
Reverse ajax in 2014Reverse ajax in 2014
Reverse ajax in 2014Nenad Pecanac
 
0-60 with Goliath: Building High Performance Ruby Web-Services
0-60 with Goliath: Building High Performance Ruby Web-Services0-60 with Goliath: Building High Performance Ruby Web-Services
0-60 with Goliath: Building High Performance Ruby Web-ServicesIlya Grigorik
 
Asterisk, HTML5 and NodeJS; a world of endless possibilities
Asterisk, HTML5 and NodeJS; a world of endless possibilitiesAsterisk, HTML5 and NodeJS; a world of endless possibilities
Asterisk, HTML5 and NodeJS; a world of endless possibilitiesDan Jenkins
 
Beyond Breakpoints: A Tour of Dynamic Analysis
Beyond Breakpoints: A Tour of Dynamic AnalysisBeyond Breakpoints: A Tour of Dynamic Analysis
Beyond Breakpoints: A Tour of Dynamic AnalysisFastly
 
Websockets in Node.js - Making them reliable and scalable
Websockets in Node.js - Making them reliable and scalableWebsockets in Node.js - Making them reliable and scalable
Websockets in Node.js - Making them reliable and scalableGareth Marland
 
Going Live! with Comet
Going Live! with CometGoing Live! with Comet
Going Live! with CometSimon Willison
 

Tendances (20)

Dancing with websocket
Dancing with websocketDancing with websocket
Dancing with websocket
 
Intro to WebSockets
Intro to WebSocketsIntro to WebSockets
Intro to WebSockets
 
HTML5 vs Silverlight
HTML5 vs SilverlightHTML5 vs Silverlight
HTML5 vs Silverlight
 
Websockets and SockJS, Real time chatting
Websockets and SockJS, Real time chattingWebsockets and SockJS, Real time chatting
Websockets and SockJS, Real time chatting
 
Handling 10k requests per second with Symfony and Varnish - SymfonyCon Berlin...
Handling 10k requests per second with Symfony and Varnish - SymfonyCon Berlin...Handling 10k requests per second with Symfony and Varnish - SymfonyCon Berlin...
Handling 10k requests per second with Symfony and Varnish - SymfonyCon Berlin...
 
Real time web (Orbited) at BCNE3
Real time web (Orbited) at BCNE3Real time web (Orbited) at BCNE3
Real time web (Orbited) at BCNE3
 
Implementing Comet using PHP
Implementing Comet using PHPImplementing Comet using PHP
Implementing Comet using PHP
 
Solving anything in VCL
Solving anything in VCLSolving anything in VCL
Solving anything in VCL
 
Websockets on the JVM: Atmosphere to the rescue!
Websockets on the JVM: Atmosphere to the rescue!Websockets on the JVM: Atmosphere to the rescue!
Websockets on the JVM: Atmosphere to the rescue!
 
A language for the Internet: Why JavaScript and Node.js is right for Internet...
A language for the Internet: Why JavaScript and Node.js is right for Internet...A language for the Internet: Why JavaScript and Node.js is right for Internet...
A language for the Internet: Why JavaScript and Node.js is right for Internet...
 
GWT Web Socket and data serialization
GWT Web Socket and data serializationGWT Web Socket and data serialization
GWT Web Socket and data serialization
 
Reverse ajax in 2014
Reverse ajax in 2014Reverse ajax in 2014
Reverse ajax in 2014
 
0-60 with Goliath: Building High Performance Ruby Web-Services
0-60 with Goliath: Building High Performance Ruby Web-Services0-60 with Goliath: Building High Performance Ruby Web-Services
0-60 with Goliath: Building High Performance Ruby Web-Services
 
About Node.js
About Node.jsAbout Node.js
About Node.js
 
Asterisk, HTML5 and NodeJS; a world of endless possibilities
Asterisk, HTML5 and NodeJS; a world of endless possibilitiesAsterisk, HTML5 and NodeJS; a world of endless possibilities
Asterisk, HTML5 and NodeJS; a world of endless possibilities
 
Beyond Breakpoints: A Tour of Dynamic Analysis
Beyond Breakpoints: A Tour of Dynamic AnalysisBeyond Breakpoints: A Tour of Dynamic Analysis
Beyond Breakpoints: A Tour of Dynamic Analysis
 
Websockets in Node.js - Making them reliable and scalable
Websockets in Node.js - Making them reliable and scalableWebsockets in Node.js - Making them reliable and scalable
Websockets in Node.js - Making them reliable and scalable
 
Going Live! with Comet
Going Live! with CometGoing Live! with Comet
Going Live! with Comet
 
Time for Comet?
Time for Comet?Time for Comet?
Time for Comet?
 
Tornado in Depth
Tornado in DepthTornado in Depth
Tornado in Depth
 

Similaire à Build Real-Time Web Apps with Play! and WebSockets

Get Real: Adventures in realtime web apps
Get Real: Adventures in realtime web appsGet Real: Adventures in realtime web apps
Get Real: Adventures in realtime web appsdaviddemello
 
Designing for Distributed Systems with Reactor and Reactive Streams
Designing for Distributed Systems with Reactor and Reactive StreamsDesigning for Distributed Systems with Reactor and Reactive Streams
Designing for Distributed Systems with Reactor and Reactive StreamsStéphane Maldini
 
Building interactivity with websockets
Building interactivity with websocketsBuilding interactivity with websockets
Building interactivity with websocketsWim Godden
 
Message in a Bottle
Message in a BottleMessage in a Bottle
Message in a BottleZohar Arad
 
Pushing Datatothe Browserwith Comet Ajax W
Pushing Datatothe Browserwith Comet Ajax WPushing Datatothe Browserwith Comet Ajax W
Pushing Datatothe Browserwith Comet Ajax Wrajivmordani
 
Interactive web. O rly?
Interactive web. O rly?Interactive web. O rly?
Interactive web. O rly?timbc
 
Real-Time Web Apps & .NET. What Are Your Options? NDC Oslo 2016
Real-Time Web Apps & .NET. What Are Your Options? NDC Oslo 2016Real-Time Web Apps & .NET. What Are Your Options? NDC Oslo 2016
Real-Time Web Apps & .NET. What Are Your Options? NDC Oslo 2016Phil Leggetter
 
Enhancing Mobile User Experience with WebSocket
Enhancing Mobile User Experience with WebSocketEnhancing Mobile User Experience with WebSocket
Enhancing Mobile User Experience with WebSocketMauricio "Maltron" Leal
 
Realtime Communication Techniques with PHP
Realtime Communication Techniques with PHPRealtime Communication Techniques with PHP
Realtime Communication Techniques with PHPWaterSpout
 
Comet from JavaOne 2008
Comet from JavaOne 2008Comet from JavaOne 2008
Comet from JavaOne 2008Joe Walker
 
Tornado web
Tornado webTornado web
Tornado webkurtiss
 
Web Sockets are not Just for Web Browsers
Web Sockets are not Just for Web BrowsersWeb Sockets are not Just for Web Browsers
Web Sockets are not Just for Web Browserscjmyers
 
Vert.x for Microservices Architecture
Vert.x for Microservices ArchitectureVert.x for Microservices Architecture
Vert.x for Microservices ArchitectureIdan Fridman
 
Setup ephemeral password for TURN, Learn RTC in less than 200 Lines of code
Setup ephemeral password for TURN, Learn RTC in less than 200 Lines of codeSetup ephemeral password for TURN, Learn RTC in less than 200 Lines of code
Setup ephemeral password for TURN, Learn RTC in less than 200 Lines of codeAmitesh Madhur
 
A language for the Internet: Why JavaScript and Node.js is right for Internet...
A language for the Internet: Why JavaScript and Node.js is right for Internet...A language for the Internet: Why JavaScript and Node.js is right for Internet...
A language for the Internet: Why JavaScript and Node.js is right for Internet...Tom Croucher
 
Message Queuing on a Large Scale: IMVUs stateful real-time message queue for ...
Message Queuing on a Large Scale: IMVUs stateful real-time message queue for ...Message Queuing on a Large Scale: IMVUs stateful real-time message queue for ...
Message Queuing on a Large Scale: IMVUs stateful real-time message queue for ...Jon Watte
 

Similaire à Build Real-Time Web Apps with Play! and WebSockets (20)

WebSockets in JEE 7
WebSockets in JEE 7WebSockets in JEE 7
WebSockets in JEE 7
 
Get Real: Adventures in realtime web apps
Get Real: Adventures in realtime web appsGet Real: Adventures in realtime web apps
Get Real: Adventures in realtime web apps
 
08 ajax
08 ajax08 ajax
08 ajax
 
Designing for Distributed Systems with Reactor and Reactive Streams
Designing for Distributed Systems with Reactor and Reactive StreamsDesigning for Distributed Systems with Reactor and Reactive Streams
Designing for Distributed Systems with Reactor and Reactive Streams
 
Building interactivity with websockets
Building interactivity with websocketsBuilding interactivity with websockets
Building interactivity with websockets
 
Message in a Bottle
Message in a BottleMessage in a Bottle
Message in a Bottle
 
Pushing Datatothe Browserwith Comet Ajax W
Pushing Datatothe Browserwith Comet Ajax WPushing Datatothe Browserwith Comet Ajax W
Pushing Datatothe Browserwith Comet Ajax W
 
Interactive web. O rly?
Interactive web. O rly?Interactive web. O rly?
Interactive web. O rly?
 
Real-Time Web Apps & .NET. What Are Your Options? NDC Oslo 2016
Real-Time Web Apps & .NET. What Are Your Options? NDC Oslo 2016Real-Time Web Apps & .NET. What Are Your Options? NDC Oslo 2016
Real-Time Web Apps & .NET. What Are Your Options? NDC Oslo 2016
 
Enhancing Mobile User Experience with WebSocket
Enhancing Mobile User Experience with WebSocketEnhancing Mobile User Experience with WebSocket
Enhancing Mobile User Experience with WebSocket
 
Realtime Communication Techniques with PHP
Realtime Communication Techniques with PHPRealtime Communication Techniques with PHP
Realtime Communication Techniques with PHP
 
Android dev 3
Android dev 3Android dev 3
Android dev 3
 
Comet from JavaOne 2008
Comet from JavaOne 2008Comet from JavaOne 2008
Comet from JavaOne 2008
 
Tornado web
Tornado webTornado web
Tornado web
 
Web Sockets are not Just for Web Browsers
Web Sockets are not Just for Web BrowsersWeb Sockets are not Just for Web Browsers
Web Sockets are not Just for Web Browsers
 
Vert.x for Microservices Architecture
Vert.x for Microservices ArchitectureVert.x for Microservices Architecture
Vert.x for Microservices Architecture
 
Setup ephemeral password for TURN, Learn RTC in less than 200 Lines of code
Setup ephemeral password for TURN, Learn RTC in less than 200 Lines of codeSetup ephemeral password for TURN, Learn RTC in less than 200 Lines of code
Setup ephemeral password for TURN, Learn RTC in less than 200 Lines of code
 
Opa hackathon
Opa hackathonOpa hackathon
Opa hackathon
 
A language for the Internet: Why JavaScript and Node.js is right for Internet...
A language for the Internet: Why JavaScript and Node.js is right for Internet...A language for the Internet: Why JavaScript and Node.js is right for Internet...
A language for the Internet: Why JavaScript and Node.js is right for Internet...
 
Message Queuing on a Large Scale: IMVUs stateful real-time message queue for ...
Message Queuing on a Large Scale: IMVUs stateful real-time message queue for ...Message Queuing on a Large Scale: IMVUs stateful real-time message queue for ...
Message Queuing on a Large Scale: IMVUs stateful real-time message queue for ...
 

Dernier

"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek SchlawackFwdays
 
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxUse of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxLoriGlavin3
 
SALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICESSALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICESmohitsingh558521
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfAlex Barbosa Coqueiro
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Manik S Magar
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024Lorenzo Miniero
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLScyllaDB
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii SoldatenkoFwdays
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteDianaGray10
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024Lonnie McRorey
 
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxPasskey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxLoriGlavin3
 
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxA Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxLoriGlavin3
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.Curtis Poe
 
Advanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionAdvanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionDilum Bandara
 
A Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersA Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersNicole Novielli
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brandgvaughan
 
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxDigital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxLoriGlavin3
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfAddepto
 
Time Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsTime Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsNathaniel Shimoni
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 

Dernier (20)

"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
 
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxUse of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
 
SALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICESSALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICES
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdf
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQL
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test Suite
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024
 
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxPasskey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
 
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxA Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.
 
Advanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionAdvanced Computer Architecture – An Introduction
Advanced Computer Architecture – An Introduction
 
A Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersA Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software Developers
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brand
 
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxDigital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdf
 
Time Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsTime Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directions
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 

Build Real-Time Web Apps with Play! and WebSockets

  • 1. Building real-time web apps using WEBSOcKeTS WITH PLAY! andrew@42go.com @connerdelights
  • 2. How we used to do it request
  • 3. How we used to do it request response
  • 4. How we used to do it request response new message!
  • 5. How we used to do it request response new message!
  • 7. The dynamic web needs real-time communication
  • 8. The dynamic web needs real-time communication
  • 12. short polling Resource intensive,slow, limited toone response
  • 14. Chunked Responses Hacky, no error handling,half-duplex
  • 18. Long Polling well supported,still half-duplex,single req/resp
  • 19. These do not handle high bursts of messages
  • 20. These do not handle high bursts of messages Stuck with the single request → response model
  • 21. GET / HTTP/1.1 Host: www.google.com Connection: keep-alive Cache-Control: max-age=0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/ 28.0.1500.71 Safari/537.36 DNT: 1 Accept-Encoding: gzip,deflate,sdch Accept-Language: en-US,en;q=0.8 Cookie: PREF=ID=e248d326d84eb3dc:FF=0:TM=1372622071:LM=1274622070:S=2bERIaHgSKRjWeC8; NID=47=CHAZZVkq40TcovIu- FuXlU0pF2UPfqqSEhNqx8hqUKnZ7-s4uxGjtBEFK7kRtTSVEu4fzJ00vhB4OrLRxw8JfV5EuiKczEC2_EHkBqr1kNwn_NdZ73XRl2umFybXYoiVD_ HTTP/1.1 200 OK Date: Tue, 23 Jul 2013 23:28:02 GMT Expires: -1 Cache-Control: private, max-age=0 Content-Type: text/html; charset=UTF-8 Set-Cookie: PREF=ID=e248d326d84eb3dc:FF=1997f24999d1d9ef:FF=0:TM=1334622374:LM=1374622082:S=ynynJppwL64C6VMRU; expires=Thu, 23-Jul-2015 23:28:02 GMT; path=/; domain=.google.com Content-Encoding: gzip Server: gws X-XSS-Protection: 1; mode=block X-Frame-Options: SAMEORIGIN Transfer-Encoding: chunked Inefficient Over 1kb in headers
  • 24. Can Play! do these? In fact, if you’re supporting older browsers, consider them! Yes!
  • 27. How fast are websockets? our office EC2 US West
  • 28. How fast are websockets? our office EC2 US West Average 10ms ping ~13ms mean improvement Full benchmarks: http://eng.42go.com/
  • 29. GET / HTTP/1.1 Host: www.google.com Connection: keep-alive Cache-Control: max-age=0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/ 28.0.1500.71 Safari/537.36 DNT: 1 Accept-Encoding: gzip,deflate,sdch Accept-Language: en-US,en;q=0.8 Cookie: PREF=ID=e248d326d84eb3dc:FF=0:TM=1372622071:LM=1274622070:S=2bERIaHgSKRjWeC8; NID=47=CHAZZVkq40TcovIu- FuXlU0pF2UPfqqSEhNqx8hqUKnZ7-s4uxGjtBEFK7kRtTSVEu4fzJ00vhB4OrLRxw8JfV5EuiKczEC2_EHkBqr1kNwn_NdZ73XRl2umFybXYoiVD_ HTTP/1.1 200 OK Date: Tue, 23 Jul 2013 23:28:02 GMT Expires: -1 Cache-Control: private, max-age=0 Content-Type: text/html; charset=UTF-8 Set-Cookie: PREF=ID=e248d326d84eb3dc:FF=1997f24999d1d9ef:FF=0:TM=1334622374:LM=1374622082:S=ynynJppwL64C6VMRU; expires=Thu, 23-Jul-2015 23:28:02 GMT; path=/; domain=.google.com Content-Encoding: gzip Server: gws X-XSS-Protection: 1; mode=block X-Frame-Options: SAMEORIGIN Transfer-Encoding: chunked Over 1kb in headers
  • 30. How fast are websockets? Initial Websocket transmission Websocket Client HTTP Client
  • 31. How fast are websockets? EC2 US West TCP Websocket 0.002ms 0.02ms Websockets are not magical :) Full benchmarks: http://eng.42go.com/
  • 32. How fast are websockets? EC2 US West TCP Websocket 0.002ms 0.02ms Still quite fast Full benchmarks: http://eng.42go.com/
  • 33. Websockets deal with streams of data from the client to the client
  • 34. What are my messages? Here’s Your messages! You have a new notification from the client to the client
  • 35. What are my messages? Here’s Your messages! You have a new notification I visited my user profile page I visited the home page from the client to the client
  • 36. What are my messages? Here’s Your messages! You have a new notification I visited my user profile page I visited the home page Here’s a Message for Frank Got your message from the client to the client
  • 37. What are my messages? Here’s Your messages! You have a new notification I visited my user profile page I visited the home page Here’s a Message for Frank Got your message Code push, reconnect please! from the client to the client
  • 40. val it = Seq(1,2,3,4,5).toIterator while(it.hasNext) { println(it.next()) } Iterators
  • 41. val it = Seq(1,2,3,4,5).toIterator while(it.hasNext) { println(it.next()) } val list = Seq(1,2,3,4,5) list.foreach(println) Iterators
  • 42. val list = Seq(1,2,3,4,5) list.foreach(println) Instead of imperatively traversing containers, apply a function to elements in a container. Iterators
  • 43. val list = Seq(1,2,3,4,5) list.foreach(println) Container Function Iterators
  • 44. Iterators val list = Seq(1,2,3,4,5) list.foreach(println) Container Function Producer Consumer
  • 45. Iteratee (ie, the consumer) Immutably consumes chunks from a Producer. Think: Iterates over a stream*.
  • 46. Iteratee (ie, the consumer) Immutably consumes chunks from a Producer. Think: Iterates over a stream*. Iteratees can actually do a bit more, but we’ll save that for another day.
  • 47. Enumerator (ie, the PRODUCER) Produces typed chunks. Only produces when there is a CONSUMER.
  • 48. Play! needs a producer and consumer for a Websocket stream
  • 49. val in = Iteratee.foreach[JsArray](println)
  • 50. val in = Iteratee.foreach[JsArray](println) Consumer This iteratee will consume from an Enumerator (the client), printing the input to the console
  • 51. val in = Iteratee.foreach[JsArray](println) val out = Enumerator("You connected!").andThen(Enumerator.eof) Producer This Enumerator will be consumed by an iteratee (The client), sending a string then EOF
  • 52. def index = WebSocket.using[JsArray] { request => val in = Iteratee.foreach[JsArray](println) val out = Enumerator("You connected!").andThen(Enumerator.eof) (in, out) }
  • 53. def index = WebSocket.using[JsArray] { request => val in = Iteratee.foreach[JsArray](println) val out = Enumerator("You connected!").andThen(Enumerator.eof) (in, out) } It works! > var createSocket = function() { var s = new WebSocket("ws://localhost:9000"); s.onopen = function() { s.send("['hey!']"); } s.onclose = function(e) { console.log("closed!",e); } s.onmessage = function(msg) { console.log("got: ", msg.data); } return s; } undefined > var socket = createSocket() undefined got: You connected! closed! CloseEvent {reason: "", code: 1005, wasClean: true, clipboardData:
  • 54. def echo = WebSocket.using[JsArray] { request => val (out, channel) = Concurrent.broadcast[JsArray] val in = Iteratee.foreach[JsArray](channel.push) (in, out) }
  • 55. def echo = WebSocket.using[JsArray] { request => val (out, channel) = Concurrent.broadcast[JsArray] val in = Iteratee.foreach[JsArray](channel.push) (in, out) } feeds into Channels let us imperatively push data into an enumerator
  • 57. Channels... how about a chat room? super simple ^
  • 58. Simplified version of the Play! Chat room websocket sample https://github.com/playframework/playframework/blob/master/samples/scala/websocket-chat
  • 59. case class Join(username: String) case class Quit(username: String) case class Talk(username: String, text: String) class ChatRoom extends Actor { var members = Set.empty[String] val (chatEnumerator, chatChannel) = Concurrent.broadcast[JsValue] val chatBot = "Marvin"   def receive = ???   }
  • 60. case class Join(username: String) case class Quit(username: String) case class Talk(username: String, text: String) class ChatRoom extends Actor { var members = Set.empty[String] val (chatEnumerator, chatChannel) = Concurrent.broadcast[JsValue] val chatBot = "Marvin"   def receive = ???   } channel output lets us push data into the enumerator
  • 61. case class Join(username: String) case class Quit(username: String) case class Talk(username: String, text: String) class ChatRoom extends Actor { var members = Set.empty[String] val (chatEnumerator, chatChannel) = Concurrent.broadcast[JsValue] val chatBot = "Marvin"   def receive = { case Join(username) => { members = members + username broadcastMessage(chatBot, s"$username has joined") sender ! chatEnumerator } case Quit(username) => case Talk(username, text) => }   def broadcastMessage(user: String, text: String): Unit = ??? }
  • 62. case class Join(username: String) case class Quit(username: String) case class Talk(username: String, text: String) class ChatRoom extends Actor { var members = Set.empty[String] val (chatEnumerator, chatChannel) = Concurrent.broadcast[JsValue] val chatBot = "Marvin"   def receive = { case Join(username) => { members = members + username broadcastMessage(chatBot, s"$username has joined") sender ! chatEnumerator } case Quit(username) => case Talk(username, text) => }   def broadcastMessage(user: String, text: String): Unit = ??? } send back a reference to the chatroom’s enumerator
  • 63. case class Join(username: String) case class Quit(username: String) case class Talk(username: String, text: String) class ChatRoom extends Actor { var members = Set.empty[String] val (chatEnumerator, chatChannel) = Concurrent.broadcast[JsValue] val chatBot = "Marvin"   def receive = { case Join(username) => { members = members + username broadcastMessage(chatBot, s"$username has joined") sender ! chatEnumerator } case Quit(username) => { broadcastMessage(chatBot, s"$username has left") members = members - username } case Talk(username, text) => broadcastMessage(username, text) }   def broadcastMessage(user: String, text: String): Unit = ??? }
  • 64. case class Join(username: String) case class Quit(username: String) case class Talk(username: String, text: String) class ChatRoom extends Actor { ...   def broadcastMessage(user: String, text: String): Unit = { val msg = Json.obj("user" -> JsString(user), "message" -> JsString(text), "members" -> JsArray(members.toList.map(JsString))) chatChannel.push(msg) } }
  • 65. object Application extends Controller { lazy val chatroomActor = Akka.system.actorOf(Props[ChatRoom])   def chat(username: String) = WebSocket.async[JsValue] { request => (chatroomActor ? Join(username)) map { // grab the Enumerator from ChatRoom: case out: Enumerator[JsValue] => val in = Iteratee.foreach[JsValue] { event => chatroomActor ! Talk(username, (event "text").as[String]) }.mapDone { _ => chatroomActor ! Quit(username) } (in, out) } } }
  • 66. This can be modified to be a lightweight pub-sub system by creating many channels Play!
  • 69. Lessons learned weird things can happen when you’re depending on a long-lived socket
  • 70. Lessons learned weird things can happen when you’re depending on a long-lived socket clients lie voodoo when packet loss is high disconnects happen
  • 71. Lessons learned babysit connections in your application ping / pong
  • 72. Lessons learned your clients need to auto-reconnect (we’ll be open sourcing our reconnecting WS library soon!)
  • 73. Lessons learned be careful about thread safety val in = Iteratee.foreach[JsArray](/* handler */)
  • 74. Lessons learned make sure this guy is fast val in = Iteratee.foreach[JsArray](/* handler */)