Real-Time Web Apps & Symfony. What are your options?

Post on 22-Feb-2017

1.760 views 1 download

Transcript of Real-Time Web Apps & Symfony. What are your options?

Real-time Web Apps & Symfony.

What are your options?

PHIL @LEGGETTERHead of Developer Relations

1 / 72

@leggetter

2 / 72

What we'll cover

1. Why Real-Time?2. What are your options

How do you choose?

Pros & Cons

3. 3 Example Solutions for Symfony

3 / 72

Why Realtime?

4 / 72

Notifications & Signalling

5 / 72

Activity Streams

6 / 72

Data Visualizations

7 / 72

8 / 72

Chat

9 / 72

Real-Time Location Tracking

10 / 72

Multi-User Collaboration

11 / 72

Multiplayer Games /

"Do some real-time art!"

12 / 72

13 / 72

Users expect a real-time UX

14 / 72

Users expect a real-time UX

Without a real-time UX your app appears

broken

15 / 72

Real-time Web Apps & Symfony.What are your options?

16 / 72

6 Factors to Consider

17 / 72

1. Use an existing solution

Don't reinvent the wheel

Unless you've a unique use case

18 / 72

Why use an existing solution?

Fallback/upgrade hacks still requiredSupport/CommunityMaintenanceFuture featuresScaling

19 / 72

20 / 72

2. Use languages you're comfortable

with

21 / 72

Solutions by language

PHP: ReactPHP, Ratchet, dNode-php, phpDaemonJava: Netty, JettyJavaScript (Node.JS): Faye, Socket.IO (Engine.IO), Primus.io.NET (C#): SignalR, XSocketsPython: Lots of options built on TornadoRuby: em-websocket, FayeLanguage agnostic: most hosted services

22 / 72

3. Native Mobile Support?

24 / 72

Native Mobile Support?

Only some have mobile librariesHow much data are you sending?SSL required on 3/4G networks

25 / 72

FayeFirebaseHydnaPubNub

PusherRatchet (via Autobahn)SignalRSocket.IO

Solutions with Native Mobile Libraries

26 / 72

4. Application/SolutionFunctionality

27 / 72

Functionality, huh?!

28 / 72

Functionality, huh?!

Communication Patterns

29 / 72

onMessage

// client

var sock = new SockJS( 'http://localhost:9999/sockjs' );

30 / 72

onMessage

// client

var sock = new SockJS( 'http://localhost:9999/sockjs' );

sock.onmessage = function( e ) {

console.log( 'message', e.data );

};

31 / 72

onMessage

// client

var sock = new SockJS( 'http://localhost:9999/sockjs' );

sock.onmessage = function( e ) {

console.log( 'message', e.data );

};

// server

sock.write( 'hello SockJS' );

32 / 72

PubSub

// client

var client = new FayeClient();

33 / 72

PubSub

// client

var client = new FayeClient();

client.subscribe( 'chat', function( message ) {

// Handle Update

} );

34 / 72

PubSub

// client

var client = new FayeClient();

client.subscribe( 'chat', function( message ) {

// Handle Update

} );

// server

var message = {

text: 'Hello, world!',

user_name: '@leggetter'

}

Faye.publish( 'chat', message );

35 / 72

Evented PubSub

// client

var pusher = new Pusher( APP_KEY );

36 / 72

Evented PubSub

// client

var pusher = new Pusher( APP_KEY );

var channel = pusher.subscribe( 'chat' );

37 / 72

Evented PubSub

// client

var pusher = new Pusher( APP_KEY );

var channel = pusher.subscribe( 'chat' );

channel.bind( 'message', function( data ) {

// Handle Update

} );

38 / 72

Evented PubSub

// client

var pusher = new Pusher( APP_KEY );

var channel = pusher.subscribe( 'chat' );

channel.bind( 'message', function( data ) {

// Handle Update

} );

channel.bind( 'message-updated', function( data ) {} );

channel.bind( 'room-name-changed', function( data ) {} );

39 / 72

Evented PubSub

// client

var pusher = new Pusher( APP_KEY );

var channel = pusher.subscribe( 'chat' );

channel.bind( 'message', function( data ) {

// Handle Update

} );

channel.bind( 'message-updated', function( data ) {} );

channel.bind( 'room-name-changed', function( data ) {} );

// server

var data = [

'text' => 'Hello, world!',

'user_name' => '@leggetter'

}

pusher->trigger( 'chat', 'message', data );

40 / 72

Data Sync

var myDataRef = new Firebase('https://yo.firebaseio.com/');

41 / 72

Data Sync

var myDataRef = new Firebase('https://yo.firebaseio.com/');

myDataRef.push( {name: '@leggetter', text: 'Yo!'} );

42 / 72

Data Sync

var myDataRef = new Firebase('https://yo.firebaseio.com/');

myDataRef.push( {name: '@leggetter', text: 'Yo!'} );

myDataRef.on( 'child_added', function(snapshot) {

// Data added

});

myDataRef.on( 'child_changed', function(snapshot) {

// Data has changed

});

myDataRef.on( 'child_removed', function(snapshot) {

// Data removed

});

43 / 72

RMI

// client

$.connection.hub.start(); // async

var chat = $.connection.chatHub;

44 / 72

RMI

// client

$.connection.hub.start(); // async

var chat = $.connection.chatHub;

chat.client.broadcastMessage = function (name, message) {

// handle message

};

45 / 72

RMI

// client

$.connection.hub.start(); // async

var chat = $.connection.chatHub;

chat.client.broadcastMessage = function (name, message) {

// handle message

};

chat.server.send( 'me', 'hello world' );

46 / 72

RMI

// client

$.connection.hub.start(); // async

var chat = $.connection.chatHub;

chat.client.broadcastMessage = function (name, message) {

// handle message

};

chat.server.send( 'me', 'hello world' );

// server

public class ChatHub : Hub

{

47 / 72

RMI

// client

$.connection.hub.start(); // async

var chat = $.connection.chatHub;

chat.client.broadcastMessage = function (name, message) {

// handle message

};

chat.server.send( 'me', 'hello world' );

// server

public class ChatHub : Hub

{

public void Send(string name, string message)

{

48 / 72

RMI

// client

$.connection.hub.start(); // async

var chat = $.connection.chatHub;

chat.client.broadcastMessage = function (name, message) {

// handle message

};

chat.server.send( 'me', 'hello world' );

// server

public class ChatHub : Hub

{

public void Send(string name, string message)

{

// Call the broadcastMessage method to update clients.

Clients.All.broadcastMessage(name, message);

}

}

49 / 72

50 / 72

51 / 72

52 / 72

5. Architecture Considerations

53 / 72

I wanna build a real-time Symfony app

or

I wanna add real-time to an existing

Symfony app

54 / 72

Self Hosted (Tightly Coupled)

55 / 72

PHP Self-Hosted options

React (PHP)Event-driven, non-blocking I/O with PHP.

Ratchet (Built on React PHP)WebSockets, WAMP, PubSub samples. No HTTP Fallback

dnode-php (RPC/RMI)phpDaemon

Lots of examples. Most docs in Russian.

56 / 72

Chris Boden, Creator/Maintainer of React (PHP) & Ratchet

“ Yes it’s possible but not common or probably

recommended yet. There are some projects that are

starting to do this by running the HTTP stack on

React [...] but it’s very uncommon at this point in

time

57 / 72

58 / 72

Self-Hosted Demo 1: Symfony + Ratchet (Loosely Coupled)

59 / 72

Pros

PHPSimple integrationStandards-based

WAMP/AutobahnJS, Android, iOS & more

Cons

No HTTP fallbackLow-level abstractionsDifferent programming styleYou need to scale

Self-Hosted Demo 1 - Pro & Cons

60 / 72

61 / 72

Self-Hosted Demo 2: Symfony + Faye (Loosely Coupled)

62 / 72

Pros

PubSubConnection fallbackIn-build Redis/Queue supportSimple integration

Cons

Not PHP(?)You need to scale

Self-Hosted Demo 2 - Pro & Cons

63 / 72

64 / 72

Hosted Demo: Pusher

65 / 72

Pros

Simple & powerfulInstantly scalableManaged & dedicatedDirect integration into Symfony

Cons

3rd party reliance

Hosted - Pros & Cons

66 / 72

6. Self-Hosted v Hosted

"Build vs. Buy"

67 / 72

Build vs. Buy - Costs

baremetrics.com/calculator

68 / 72

How do you choose?

6 Realtime Framework Considerations

1. Use an Existing Solution2. Use a language you're comfortable with3. Do you need native mobile support?4. onMessage, PubSub (Evented), RMI or DataSync5. Architectural considerations6. Hosted v Self-Hosted (Build vs. Buy)

69 / 72

You need Real-Time!

There are lots of options.

Make the choice that's right for you.

I hope this helps!

70 / 72

Resources

Real-time Tech GuideReact (PHP)Ratchet (PHP)Faye (Node/Ruby)PusherLopiPusherBundlegithub.com/leggetter/realtime-symfony-examples

71 / 72

Real-time Web Apps & Symfony.

What are your options?

Questions?

joind.in/14980 | leggetter.github.io/realtime-symfony

PHIL @LEGGETTERHead of Developer Relations

72 / 72