SlideShare a Scribd company logo
SOMETIMES
WEBSOCKETS
DON’T WORK
   @pawel_ledwon
Sometimes web sockets_dont_work
WE DO
WEBSOCKETS
  …and a bit more
REASONS TO LOVE
WebSockets
 persistent and bi-directional
 very straightforward API
 don’t incur too much latency
var websocket = new WebSocket("ws://example.com");

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

websocket.onmessage = function(message) {
   console.log("BEEP", message.data);
};
DONE!
NOPE!
WHAT’S THE ISSUE?

1.ancient browsers
2.corporate firewalls
3.restrictive proxies
          ...
L E T ’S
SOLVE
THEM!
PRIMARY OBJECTIVES

1.improve connectivity
2.provide clients with
  best possible transport
3.improve initial latency
SECONDARY OBJECTIVES

1.keep costs reasonable
2.gather some metrics
3.allow experimenting
DESIGN
TRANSPORT


a type of
connection
DIFFERENT TRANSPORTS

     WebSockets
        Flash
     HTTP-based
    (SSL/Non-SSL)
TRANSPORT CLASS


Transport.connect(url)

          ...
STRATEGY

a recipe for finding
best working
transport
STRATEGIES SHOULD BE

 1.quick and effective
 2.easy to understand
 3.also easy to test
 4.simple to modify
BACK TO OUR PROBLEMS

  1.ancient browsers
  2.corporate firewalls
  3.restrictive proxies
ANCIENT BROWSERS

easiest problem to solve
   client-side checks
no communication needed
if (WebSocketTransport.isSupported()) {
  return WebSocketTransport;
} else if (FlashTransport.isSupported()) {
  return FlashTransport;
} else {
  return HTTPTransport;
}
TRANSPORT CLASS


Transport.connect(url)
Transport.isSupported()
BACK TO OUR PROBLEMS

  1.ancient browsers
  2.corporate firewalls
  3.restrictive proxies
FLASH & FIREWALLS

 neeeds port 843 to be open or…
waits 3s before trying original port
                 …
  you never know what’s coming
FLASH IS NOT THAT BAD

1.it’s basically a WebSocket
2.has low message latency
3.requires less infrastructure
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.switch to Flash
CONNECTING IN PARALLEL
       Flash
a)     HTTP



       Flash
b)     HTTP



       Flash
c)     HTTP
BACK TO OUR PROBLEMS

  1.ancient browsers
  2.corporate firewalls
  3.restrictive proxies
WEBSOCKETS & PROXIES

  some work just fine
    some are too old
  some just hate us all
WEBSOCKETS & PROXIES

issues with upgrading
frequent disconnections
same issue with Flash
DEALING WITH IT

1.handle WebSockets like Flash
2.use encrypted connections
3.detect broken connections
4.disable transports temporarily
CACHING


1.run full strategy on 1st attempt
2.cache info about best transport
3.use cache on subsequent attempts
STRATEGIES - RECAP

detect browser features   cache transport info
  connect in parallel     detect disconnections
    retry attempts         disable transports
    support delays          support timeouts
IMPLEMENTATION
SINGLE RESPONSIBILITY PRINCIPLE

     one decision per strategy
         simple interface
        lots different types
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();
COMPOSING STRATEGIES

      strategies form trees
  they can use other strategies
decisions are still simple and local
STRATEGIES
1.transport           provides transport to strategy adapter
2.if                  runs a test and choses another strategy
3.best connected      runs in parallel to find best strategy
4.sequential          runs strategies sequentially
5.delayed             runs a strategy with a delay
6.cached              stores and fetches cached transport info
7.first connected     terminates a strategy on first connection
transport



  ws
sequential


transport



   ws
sequential   sequential


transport    transport



   ws        sockjs
delayed


sequential   sequential


transport    transport



   ws        sockjs
best connected


                    delayed


sequential         sequential


transport          transport



   ws              sockjs
if
         ws.isSupported()

                     true

        best connected


                            delayed


sequential             sequential


transport              transport



   ws                   sockjs
if
         ws.isSupported()

                     true             false

        best connected                        sequential


                            delayed           transport


sequential             sequential
                                              sockjs
transport              transport



   ws                   sockjs
cached

                if
         ws.isSupported()

                     true                      false

        best connected                                 sequential


                            delayed                    transport


sequential             sequential
                                                       sockjs
transport              transport



   ws                   sockjs
REPRESENTATION
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
SENDING JS IS NOT AN OPTION

      1.it’s dangerous
      2.too expressive
      3.difficult to test
JSON

1.has no side-effects
2.widely supported
3.known by everyone
JSON



needs an interpreter
DESIRABLE FEATURES

1.ability to define variables
2.passing by reference
3.predictable execution
4.limited expressiveness
[
    [":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"
           ]
        ]]
      ]
    ]
]
[
     [":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"
           ]
        ]]
      ]
    ]
]
[
    [":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"
           ]
        ]]
      ]
    ]
]
[
    [":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"
            ]
         ]]
       ]
     ]
]
METRICS
WE COLLECT


1.transport state changes
2.browser name, features
3.some strategy actions
BETA DEPLOYMENTS

1.deploy a new feature
2.wait for enough data
3.evaluate all metrics
4.keep or revert changes
THANKS!

  @pawel_ledwon

More Related Content

KEY
Esperwhispering
PPTX
동시성과 병렬성
PDF
Cache is King - RubyHACK 2019
PDF
Cache is King: RubyConf Columbia
PDF
Couchdb w Ruby'm
PDF
Sensmon couchdb
PDF
Interactive subway map
PPTX
Hands on Data Grids - Stephen Milidge
Esperwhispering
동시성과 병렬성
Cache is King - RubyHACK 2019
Cache is King: RubyConf Columbia
Couchdb w Ruby'm
Sensmon couchdb
Interactive subway map
Hands on Data Grids - Stephen Milidge

Similar to Sometimes web sockets_dont_work (20)

PDF
Hacking the Mesh: Extending Istio with WebAssembly Modules | DevNation Tech Talk
PDF
Node.js - async for the rest of us.
KEY
Socket.io
PDF
From Node to Go
PPTX
Building and Deploying Application to Apache Mesos
PDF
Guaranteeing Memory Safety in Rust
PPTX
Apache Kafka, HDFS, Accumulo and more on Mesos
PPTX
Introduction To Apache Mesos
PPT
Secure Mashups
PPTX
Hazelcast and MongoDB at Cloud CMS
KEY
HTML5 vs Silverlight
PPT
Java concurrency introduction
PDF
JRuby with Java Code in Data Processing World
PDF
Comet with node.js and V8
PDF
Meder Kydyraliev - Mining Mach Services within OS X Sandbox
PDF
Service-Oriented Integration With Apache ServiceMix
PDF
DEVIEW - 오픈소스를 활용한 분산아키텍처 구현기술
PDF
Rust Intro @ Roma Rust meetup
PPT
JS everywhere 2011
PDF
Designing a Scalable Data Platform
Hacking the Mesh: Extending Istio with WebAssembly Modules | DevNation Tech Talk
Node.js - async for the rest of us.
Socket.io
From Node to Go
Building and Deploying Application to Apache Mesos
Guaranteeing Memory Safety in Rust
Apache Kafka, HDFS, Accumulo and more on Mesos
Introduction To Apache Mesos
Secure Mashups
Hazelcast and MongoDB at Cloud CMS
HTML5 vs Silverlight
Java concurrency introduction
JRuby with Java Code in Data Processing World
Comet with node.js and V8
Meder Kydyraliev - Mining Mach Services within OS X Sandbox
Service-Oriented Integration With Apache ServiceMix
DEVIEW - 오픈소스를 활용한 분산아키텍처 구현기술
Rust Intro @ Roma Rust meetup
JS everywhere 2011
Designing a Scalable Data Platform
Ad

Recently uploaded (20)

PDF
Getting Started with Data Integration: FME Form 101
PPT
Teaching material agriculture food technology
PDF
cuic standard and advanced reporting.pdf
PPTX
1. Introduction to Computer Programming.pptx
PDF
Assigned Numbers - 2025 - Bluetooth® Document
PDF
Accuracy of neural networks in brain wave diagnosis of schizophrenia
PDF
Optimiser vos workloads AI/ML sur Amazon EC2 et AWS Graviton
PPTX
Big Data Technologies - Introduction.pptx
PDF
Machine learning based COVID-19 study performance prediction
PPTX
Programs and apps: productivity, graphics, security and other tools
PDF
Mobile App Security Testing_ A Comprehensive Guide.pdf
PPTX
Digital-Transformation-Roadmap-for-Companies.pptx
PDF
Unlocking AI with Model Context Protocol (MCP)
PDF
Agricultural_Statistics_at_a_Glance_2022_0.pdf
PPTX
A Presentation on Artificial Intelligence
PPTX
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
PDF
Electronic commerce courselecture one. Pdf
PDF
The Rise and Fall of 3GPP – Time for a Sabbatical?
PPTX
20250228 LYD VKU AI Blended-Learning.pptx
PDF
A comparative analysis of optical character recognition models for extracting...
Getting Started with Data Integration: FME Form 101
Teaching material agriculture food technology
cuic standard and advanced reporting.pdf
1. Introduction to Computer Programming.pptx
Assigned Numbers - 2025 - Bluetooth® Document
Accuracy of neural networks in brain wave diagnosis of schizophrenia
Optimiser vos workloads AI/ML sur Amazon EC2 et AWS Graviton
Big Data Technologies - Introduction.pptx
Machine learning based COVID-19 study performance prediction
Programs and apps: productivity, graphics, security and other tools
Mobile App Security Testing_ A Comprehensive Guide.pdf
Digital-Transformation-Roadmap-for-Companies.pptx
Unlocking AI with Model Context Protocol (MCP)
Agricultural_Statistics_at_a_Glance_2022_0.pdf
A Presentation on Artificial Intelligence
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
Electronic commerce courselecture one. Pdf
The Rise and Fall of 3GPP – Time for a Sabbatical?
20250228 LYD VKU AI Blended-Learning.pptx
A comparative analysis of optical character recognition models for extracting...
Ad

Sometimes web sockets_dont_work

  • 3. WE DO WEBSOCKETS …and a bit more
  • 4. REASONS TO LOVE WebSockets persistent and bi-directional very straightforward API don’t incur too much latency
  • 5. var websocket = new WebSocket("ws://example.com"); websocket.onopen = function() { websocket.send("Howdy!"); }; websocket.onmessage = function(message) { console.log("BEEP", message.data); };
  • 8. WHAT’S THE ISSUE? 1.ancient browsers 2.corporate firewalls 3.restrictive proxies ...
  • 9. L E T ’S SOLVE THEM!
  • 10. PRIMARY OBJECTIVES 1.improve connectivity 2.provide clients with best possible transport 3.improve initial latency
  • 11. SECONDARY OBJECTIVES 1.keep costs reasonable 2.gather some metrics 3.allow experimenting
  • 14. DIFFERENT TRANSPORTS WebSockets Flash HTTP-based (SSL/Non-SSL)
  • 16. STRATEGY a recipe for finding best working transport
  • 17. STRATEGIES SHOULD BE 1.quick and effective 2.easy to understand 3.also easy to test 4.simple to modify
  • 18. BACK TO OUR PROBLEMS 1.ancient browsers 2.corporate firewalls 3.restrictive proxies
  • 19. ANCIENT BROWSERS easiest problem to solve client-side checks no communication needed
  • 20. if (WebSocketTransport.isSupported()) { return WebSocketTransport; } else if (FlashTransport.isSupported()) { return FlashTransport; } else { return HTTPTransport; }
  • 22. BACK TO OUR PROBLEMS 1.ancient browsers 2.corporate firewalls 3.restrictive proxies
  • 23. FLASH & FIREWALLS neeeds port 843 to be open or… waits 3s before trying original port … you never know what’s coming
  • 24. FLASH IS NOT THAT BAD 1.it’s basically a WebSocket 2.has low message latency 3.requires less infrastructure
  • 25. 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.switch to Flash
  • 26. CONNECTING IN PARALLEL Flash a) HTTP Flash b) HTTP Flash c) HTTP
  • 27. BACK TO OUR PROBLEMS 1.ancient browsers 2.corporate firewalls 3.restrictive proxies
  • 28. WEBSOCKETS & PROXIES some work just fine some are too old some just hate us all
  • 29. WEBSOCKETS & PROXIES issues with upgrading frequent disconnections same issue with Flash
  • 30. DEALING WITH IT 1.handle WebSockets like Flash 2.use encrypted connections 3.detect broken connections 4.disable transports temporarily
  • 31. CACHING 1.run full strategy on 1st attempt 2.cache info about best transport 3.use cache on subsequent attempts
  • 32. STRATEGIES - RECAP detect browser features cache transport info connect in parallel detect disconnections retry attempts disable transports support delays support timeouts
  • 34. SINGLE RESPONSIBILITY PRINCIPLE one decision per strategy simple interface lots different types
  • 35. 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();
  • 36. COMPOSING STRATEGIES strategies form trees they can use other strategies decisions are still simple and local
  • 37. STRATEGIES 1.transport provides transport to strategy adapter 2.if runs a test and choses another strategy 3.best connected runs in parallel to find best strategy 4.sequential runs strategies sequentially 5.delayed runs a strategy with a delay 6.cached stores and fetches cached transport info 7.first connected terminates a strategy on first connection
  • 40. sequential sequential transport transport ws sockjs
  • 41. delayed sequential sequential transport transport ws sockjs
  • 42. best connected delayed sequential sequential transport transport ws sockjs
  • 43. if ws.isSupported() true best connected delayed sequential sequential transport transport ws sockjs
  • 44. if ws.isSupported() true false best connected sequential delayed transport sequential sequential sockjs transport transport ws sockjs
  • 45. cached if ws.isSupported() true false best connected sequential delayed transport sequential sequential sockjs transport transport ws sockjs
  • 47. 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
  • 48. SENDING JS IS NOT AN OPTION 1.it’s dangerous 2.too expressive 3.difficult to test
  • 49. JSON 1.has no side-effects 2.widely supported 3.known by everyone
  • 51. DESIRABLE FEATURES 1.ability to define variables 2.passing by reference 3.predictable execution 4.limited expressiveness
  • 52. [ [":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" ] ]] ] ] ]
  • 53. [ [":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" ] ]] ] ] ]
  • 54. [ [":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" ] ]] ] ] ]
  • 55. [ [":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" ] ]] ] ] ]
  • 57. WE COLLECT 1.transport state changes 2.browser name, features 3.some strategy actions
  • 58. BETA DEPLOYMENTS 1.deploy a new feature 2.wait for enough data 3.evaluate all metrics 4.keep or revert changes