Date post: | 03-Jul-2015 |
Category: |
Technology |
Upload: | fabrice-croiseaux |
View: | 1,497 times |
Download: | 3 times |
Patterns de développement pour une application Web réactive et concurrente
25/10/2013
Qui sommes-nous ? @fXzo @antoined
De quoi allons nous vous parler ? • Un concours : Typesafe Developer Contest • Une application : Car Race Dashboard • Quelques cas d’utilisation des Actors Akka
et des Iteratees
Des patterns pour... • Effectuer des traitements asynchrones • Gérer des états dans notre application • Travailler avec un stream d’événements
L’application
Nb file Nb lines Avg lines scala 9 770 86 coffee 7 343 49 html 4 275 68
Environ 20 heures de travail sur une semaine
Le résultat « Fabrice and Antoine have designed an app that is simply awesome, and a very, very close runner up to the winner. It’s far more than just a sample… and the judge were truly wowed»
https://github.com/intechgrp/CarRaceDashboard
Démo
Architecture globale
Simulation
Race
Car Car Car Car Car
Track = List [TrackPoint]
Navigateur
Moteur
Flux SSE
Navigateur
RTevListener RTevListener
Akka.system.eventStream
Stream.events: Enumerator Storage MongoDB
Stats
Architecture globale
Simulation
Race
Car Car Car Car Car
Track = List [TrackPoint]
Navigateur
Moteur
Flux SSE
Navigateur
RTevListener RTevListener
Akka.system.eventStream
Stream.events: Enumerator Storage MongoDB
Stats
La course
case class Position(latitude: Double, longitude: Double)
case class TrackPoint(id: Int, position: Position)
type Track = List[TrackPoint]
Déplacement des voitures
//return new CheckPoint on the track at distance d from point
private def next(point: TrackPoint, d: Double): TrackPoint
La Simulation - CarActor • Un Acteur Akka par coureur
o Gère l’état courant du coureur : sa position actuelle, sa vitesse instantanée, la distance parcourue
o Réagit à différents messages : § “move” : se déplace à la position suivante § “start” : début de la course, c.a.d. schedule
l’envoi de messages “move” § “getState” : retourne l’état courant
La Simulation - RaceActor • Un Acteur Akka pour gérer tous les coureurs
o Envoie le message “start” à tous les coureurs au démarrage de la course : utilisation d’un BroadcastRouter
router = context.actorOf(Props[CarActor].withRouter(akka.routing.BroadcastRouter(currentRace.get.carActors)))
/ Fire start event : broadcast the event to all CarActors
router ! "start"
Architecture globale
Simulation
Race
Car Car Car Car Car
Track = List [TrackPoint]
Navigateur
Moteur
Flux SSE
Navigateur
RTevListener RTevListener
Akka.system.eventStream
Stream.events: Enumerator Storage MongoDB
Stats
La Simulation - RaceActor o Produit le flux d’événements à partir des CarActor et
le lie au Moteur
→ pour chaque événement produit par Streams, transmet l’événement au Moteur (“StorageActor”)
// Connect the event stream to the storage actor
new Streams(currentRace.get).events(Iteratee.foreach[models.Events.Event] {
event => models.StorageActor.actor ! event
})
Architecture globale
Simulation
Race
Car Car Car Car Car
Track = List [TrackPoint]
Navigateur
Moteur
Flux SSE
Navigateur
RTevListener RTevListener
Akka.system.eventStream
Stream.events: Enumerator Storage MongoDB
Stats
• Le moteur est un acteur Akka recevant tous les événements émis par tous les véhicules
• Pour chaque événement reçu, l’acteur : o Publie l’événement sur le stream d’événements
Akka o Stocke l’événement dans une collection MongoDB
Le moteur
Le moteur • Un autre acteur (StatsActor) est planifié pour calculer
régulièrement des statistiques (vitesse moyenne, min, max, …) par voiture
• Cet acteur se base sur les données insérées dans MongoDB
• Pour chaque statistique calculée, l’actor publie un message dans l’eventStream Akka
Architecture globale
Simulation
Race
Car Car Car Car Car
Track = List [TrackPoint]
Navigateur
Moteur
Flux SSE
Navigateur
RTevListener RTevListener
Akka.system.eventStream
Stream.events: Enumerator Storage MongoDB
Stats
Flux SSE • Pour chaque navigateur accédant à l’application, un
acteur « RTEventListener » est créé • Cet acteur est à l’écoute de l’eventStream Akka • Pour chaque message sur ce stream, l’acteur envoie
dans le flux Server Sent Event une représentation JSON du message
Interface • Au niveau de l’interface HTML5, le flux SSE est
connecté avec l’objet JavaScript « EventSource » • Pour chaque message reçu sur ce flux, l’interface est
mise à jour en fonction du type d’événement : • Nouvelle position : déplace la voiture concernée • Statistiques : met à jour le récapitulatif • Vitesse instantée / distance parcourue : met à jour le compteur
Merci !
Questions ?