sometimes web sockets_dont_work

59
SOMETIMES WEBSOCKETS DON’T WORK @pawel_ledwon

Upload: xmppuk

Post on 29-Jun-2015

736 views

Category:

Technology


0 download

DESCRIPTION

Presentation by Pawel Ledwon at the 1st XMPP / Realtime Meetup

TRANSCRIPT

Page 1: Sometimes web sockets_dont_work

SOMETIMES WEBSOCKETS DON’T WORK

@pawel_ledwon

Page 2: Sometimes web sockets_dont_work
Page 3: Sometimes web sockets_dont_work

WE DO WEBSOCKETS

…and a bit more

Page 4: Sometimes web sockets_dont_work

REASONS TO LOVE

persistent and bi-directional

very straightforward API

don’t incur too much latency

WebSockets

Page 5: Sometimes web sockets_dont_work

var websocket = new WebSocket("ws://example.com");

websocket.onopen = function() { websocket.send("Howdy!");};

websocket.onmessage = function(message) { console.log("BEEP", message.data);};

Page 6: Sometimes web sockets_dont_work

DONE!

Page 7: Sometimes web sockets_dont_work

NOPE!

Page 8: Sometimes web sockets_dont_work

1.ancient browsers

2.corporate firewalls

3.restrictive proxies

WHAT’S THE ISSUE?

...

Page 9: Sometimes web sockets_dont_work

L E T ’SSOLVETHEM!

Page 10: Sometimes web sockets_dont_work

1.improve connectivity

2.provide cl ients with

best possible transport

3.improve initial latency

PRIMARY OBJECTIVES

Page 11: Sometimes web sockets_dont_work

1.keep costs reasonable

2.gather some metrics

3.allow experimenting

SECONDARY OBJECTIVES

Page 12: Sometimes web sockets_dont_work

DESIGN

Page 13: Sometimes web sockets_dont_work

a t y p e o f

connection

TRANSPORT

Page 14: Sometimes web sockets_dont_work

WebSockets

Flash

HTTP-based

(SSL/Non-SSL)

DIFFERENT TRANSPORTS

Page 15: Sometimes web sockets_dont_work

Transport.connect(url)

...

TRANSPORT CLASS

Page 16: Sometimes web sockets_dont_work

a recipe for finding

b e s t wo r k i n g

t r a n s p o r t

STRATEGY

Page 17: Sometimes web sockets_dont_work

1.quick and effective

2.easy to understand

3.also easy to test

4.simple to modify

STRATEGIES SHOULD BE

Page 18: Sometimes web sockets_dont_work

1.a n c i e n t b rows e r s

2.corporate firewalls

3.restrictive proxies

BACK TO OUR PROBLEMS

Page 19: Sometimes web sockets_dont_work

ANCIENT BROWSERS

easiest problem to solve

client-side checks

no communication needed

Page 20: Sometimes web sockets_dont_work

if (WebSocketTransport.isSupported()) { return WebSocketTransport;} else if (FlashTransport.isSupported()) { return FlashTransport;} else { return HTTPTransport;}

Page 21: Sometimes web sockets_dont_work

Transport.connect(url)

Transport.isSupported()

TRANSPORT CLASS

Page 22: Sometimes web sockets_dont_work

1.ancient browsers

2.corporate firewalls

3.restrictive proxies

BACK TO OUR PROBLEMS

Page 23: Sometimes web sockets_dont_work

FLASH & FIREWALLS

neeeds port 843 to be open or…

waits 3s before trying original port

you never know what’s coming

Page 24: Sometimes web sockets_dont_work

FLASH IS NOT THAT BAD

1.it’s basically a WebSocket

2.has low message latency

3.requires less infrastructure

Page 25: Sometimes web sockets_dont_work

DIFFERENT SOLUTIONS

1.give up and avoid Flash

2.wait and switch to HTTP

3.try Flash & HTTP in parallel

1.use first connected

2.s w i tc h to F l a s h

Page 26: Sometimes web sockets_dont_work

CONNECTING IN PARALLEL

a)

b)

c)

Flash

HTTP

Flash

HTTP

Flash

HTTP

Page 27: Sometimes web sockets_dont_work

1.ancient browsers

2.corporate firewalls

3.restrictive proxies

BACK TO OUR PROBLEMS

Page 28: Sometimes web sockets_dont_work

WEBSOCKETS & PROXIES

some work just fine

some are too old

some just hate us all

Page 29: Sometimes web sockets_dont_work

WEBSOCKETS & PROXIES

issues with upgrading

frequent disconnections

same issue with Flash

Page 30: Sometimes web sockets_dont_work

DEALING WITH IT

1.handle WebSockets like Flash

2.use encrypted connections

3.detect broken connections

4.disable transports temporarily

Page 31: Sometimes web sockets_dont_work

CACHING

1.run full strategy on 1st attempt

2.cache info about best transport

3.use cache on subsequent attempts

Page 32: Sometimes web sockets_dont_work

STRATEGIES - RECAP

detect browser features

connect in parallel

retry attempts

support delays

cache transport info

detect disconnections

disable transports

support timeouts

Page 33: Sometimes web sockets_dont_work

IMPLEMENTATION

Page 34: Sometimes web sockets_dont_work

SINGLE RESPONSIBILITY PRINCIPLE

one decision per strategy

simple interface

lots different types

Page 35: Sometimes web sockets_dont_work

var runner = strategy.connect(function(error, connection) { if (error) { console.log(":("); } else { // we can even get multiple connections console.log("We’ve got a connection!"); }});

// ok, it has been long enough, I’m giving up

runner.abort();

Page 36: Sometimes web sockets_dont_work

COMPOSING STRATEGIES

strategies form trees

they can use other strategies

decisions are still simple and local

Page 37: Sometimes web sockets_dont_work

STRATEGIES

1.transport

2.if

3.best connected

4.sequential

5.delayed

6.cached

7.first connected

provides transport to strategy adapter

runs a test and choses another strategy

runs in parallel to find best strategy

runs strategies sequentially

runs a strategy with a delay

stores and fetches cached transport info

terminates a strategy on first connection

Page 38: Sometimes web sockets_dont_work

ws

transport

Page 39: Sometimes web sockets_dont_work

ws

transport

sequential

Page 40: Sometimes web sockets_dont_work

ws sockjs

transport transport

sequentialsequential

Page 41: Sometimes web sockets_dont_work

ws sockjs

transport transport

delayed

sequentialsequential

Page 42: Sometimes web sockets_dont_work

ws sockjs

transport transport

delayed

sequentialsequential

best connected

Page 43: Sometimes web sockets_dont_work

ws sockjs

transport transport

ifws.isSupported()

delayed

sequentialsequential

best connected

true

Page 44: Sometimes web sockets_dont_work

ws sockjs

transport transport

ifws.isSupported()

delayed

sequentialsequential

best connected

sockjs

transport

sequential

true false

Page 45: Sometimes web sockets_dont_work

ws sockjs

transport transport

ifws.isSupported()

delayed

sequentialsequential

best connected

cached

sockjs

transport

sequential

true false

Page 46: Sometimes web sockets_dont_work

REPRESENTATION

Page 47: Sometimes web sockets_dont_work

REPRESENTATION SHOULD BE

1.understandable by humans

2.easy to read in JavaScript

3.possible to send to clients

4.simple to modify and test

Page 48: Sometimes web sockets_dont_work

1.it’s dangerous

2.too expressive

3.difficult to test

SENDING JS IS NOT AN OPTION

Page 49: Sometimes web sockets_dont_work

JSON

1.has no side-effects

2.widely supported

3.known by everyone

Page 50: Sometimes web sockets_dont_work

needs an interpreter

JSON

Page 51: Sometimes web sockets_dont_work

DESIRABLE FEATURES

1.ability to define variables

2.passing by reference

3.predictable execution

4.limited expressiveness

Page 52: Sometimes web sockets_dont_work

[ [":def", "ws_options", { hostUnencrypted: Pusher.host + ":" + Pusher.ws_port, hostEncrypted: Pusher.host + ":" + Pusher.wss_port, lives: 2 }], [":def", "sockjs_options", { hostUnencrypted: Pusher.sockjs_host + ":" + Pusher.sockjs_http_port, hostEncrypted: Pusher.sockjs_host + ":" + Pusher.sockjs_https_port }], [":def", "timeouts", { loop: true, timeout: 15000, timeoutLimit: 60000 }],

[":def_transport", "ws", "ws", 3, ":ws_options"], [":def_transport", "sockjs", "sockjs", 1, ":sockjs_options"], [":def", "ws_loop", [":sequential", ":timeouts", ":ws"]], [":def", "sockjs_loop", [":sequential", ":timeouts", ":sockjs"]],

[":def", "strategy", [":cached", 1800000, [":if", [":is_supported", ":ws"], [ ":best_connected_ever", ":ws_loop", [":delayed", 2000, [":sockjs_loop"]] ], [ ":sockjs_loop" ] ]] ] ]]

Page 53: Sometimes web sockets_dont_work

[

[":def", "ws_options", { hostUnencrypted: Pusher.host + ":" + Pusher.ws_port, hostEncrypted: Pusher.host + ":" + Pusher.wss_port, lives: 2 }], [":def", "sockjs_options", { hostUnencrypted: Pusher.sockjs_host + ":" + Pusher.sockjs_http_port, hostEncrypted: Pusher.sockjs_host + ":" + Pusher.sockjs_https_port }], [":def", "timeouts", { loop: true, timeout: 15000, timeoutLimit: 60000 }],

[":def_transport", "ws", "ws", 3, ":ws_options"], [":def_transport", "sockjs", "sockjs", 1, ":sockjs_options"], [":def", "ws_loop", [":sequential", ":timeouts", ":ws"]], [":def", "sockjs_loop", [":sequential", ":timeouts", ":sockjs"]],

[":def", "strategy", [":cached", 1800000, [":if", [":is_supported", ":ws"], [ ":best_connected_ever", ":ws_loop", [":delayed", 2000, [":sockjs_loop"]] ], [ ":sockjs_loop" ] ]] ] ]

]

Page 54: Sometimes web sockets_dont_work

[ [":def", "ws_options", { hostUnencrypted: Pusher.host + ":" + Pusher.ws_port, hostEncrypted: Pusher.host + ":" + Pusher.wss_port, lives: 2 }], [":def", "sockjs_options", { hostUnencrypted: Pusher.sockjs_host + ":" + Pusher.sockjs_http_port, hostEncrypted: Pusher.sockjs_host + ":" + Pusher.sockjs_https_port }], [":def", "timeouts", { loop: true, timeout: 15000, timeoutLimit: 60000 }],

[":def_transport", "ws", "ws", 3, ":ws_options"], [":def_transport", "sockjs", "sockjs", 1, ":sockjs_options"], [":def", "ws_loop", [":sequential", ":timeouts", ":ws"]], [":def", "sockjs_loop", [":sequential", ":timeouts", ":sockjs"]], [":def", "strategy", [":cached", 1800000, [":if", [":is_supported", ":ws"], [ ":best_connected_ever", ":ws_loop", [":delayed", 2000, [":sockjs_loop"]] ], [ ":sockjs_loop" ] ]] ] ]

]

Page 55: Sometimes web sockets_dont_work

[ [":def", "ws_options", { hostUnencrypted: Pusher.host + ":" + Pusher.ws_port, hostEncrypted: Pusher.host + ":" + Pusher.wss_port, lives: 2 }], [":def", "sockjs_options", { hostUnencrypted: Pusher.sockjs_host + ":" + Pusher.sockjs_http_port, hostEncrypted: Pusher.sockjs_host + ":" + Pusher.sockjs_https_port }], [":def", "timeouts", { loop: true, timeout: 15000, timeoutLimit: 60000 }],

[":def_transport", "ws", "ws", 3, ":ws_options"], [":def_transport", "sockjs", "sockjs", 1, ":sockjs_options"], [":def", "ws_loop", [":sequential", ":timeouts", ":ws"]], [":def", "sockjs_loop", [":sequential", ":timeouts", ":sockjs"]],

[":def", "strategy", [":cached", 1800000, [":if", [":is_supported", ":ws"], [ ":best_connected_ever", ":ws_loop", [":delayed", 2000, [":sockjs_loop"]] ], [ ":sockjs_loop" ] ]] ] ]]

Page 56: Sometimes web sockets_dont_work

METRICS

Page 57: Sometimes web sockets_dont_work

WE COLLECT

1.transport state changes

2.browser name, features

3.some strategy actions

Page 58: Sometimes web sockets_dont_work

BETA DEPLOYMENTS

1.deploy a new feature

2.wait for enough data

3.evaluate all metrics

4.keep or revert changes

Page 59: Sometimes web sockets_dont_work

THANKS!

@pawel_ledwon