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

Similar to Sometimes web sockets_dont_work (20)

PDF
Real Time Web - What's that for?
Martyn Loughran
 
ODP
SockJS Intro
Ngoc Dao
 
PPTX
WebSocket protocol
Kensaku Komatsu
 
PDF
Comet with node.js and V8
amix3k
 
KEY
Socket.io
Timothy Fitz
 
PDF
Real-Time with Flowdock
Flowdock
 
KEY
Realtime rocks
Vanbosse
 
KEY
Socket applications
João Moura
 
PDF
WebSocket Push Fallback - Transcript.pdf
ShaiAlmog1
 
PDF
Building real time apps with node.js, socket.io, knockout.js
betabeers
 
PDF
Socket.io
Diego Pacheco
 
PDF
Real-Time Web Apps & Symfony. What are your options?
Phil Leggetter
 
PDF
Introduction to WebSockets
Gunnar Hillert
 
PDF
Intro to Sail.js
Nicholas McClay
 
PDF
Real-Time Web Apps & .NET. What Are Your Options? NDC Oslo 2016
Phil Leggetter
 
PDF
Real time web apps
Sepehr Rasouli
 
PDF
HTML5/JavaScript Communication APIs - DPC 2014
Christian Wenz
 
PPTX
SenchaCon 2016: How to Give your Sencha App Real-time Web Performance - James...
Sencha
 
PPT
Web-Socket
Pankaj Kumar Sharma
 
PPTX
Websockets and SockJS, Real time chatting
University of Alabama at Birmingham
 
Real Time Web - What's that for?
Martyn Loughran
 
SockJS Intro
Ngoc Dao
 
WebSocket protocol
Kensaku Komatsu
 
Comet with node.js and V8
amix3k
 
Socket.io
Timothy Fitz
 
Real-Time with Flowdock
Flowdock
 
Realtime rocks
Vanbosse
 
Socket applications
João Moura
 
WebSocket Push Fallback - Transcript.pdf
ShaiAlmog1
 
Building real time apps with node.js, socket.io, knockout.js
betabeers
 
Socket.io
Diego Pacheco
 
Real-Time Web Apps & Symfony. What are your options?
Phil Leggetter
 
Introduction to WebSockets
Gunnar Hillert
 
Intro to Sail.js
Nicholas McClay
 
Real-Time Web Apps & .NET. What Are Your Options? NDC Oslo 2016
Phil Leggetter
 
Real time web apps
Sepehr Rasouli
 
HTML5/JavaScript Communication APIs - DPC 2014
Christian Wenz
 
SenchaCon 2016: How to Give your Sencha App Real-time Web Performance - James...
Sencha
 
Websockets and SockJS, Real time chatting
University of Alabama at Birmingham
 

Recently uploaded (20)

PDF
The Past, Present & Future of Kenya's Digital Transformation
Moses Kemibaro
 
PDF
Bitcoin+ Escalando sin concesiones - Parte 1
Fernando Paredes García
 
PDF
Empowering Cloud Providers with Apache CloudStack and Stackbill
ShapeBlue
 
PDF
"Effect, Fiber & Schema: tactical and technical characteristics of Effect.ts"...
Fwdays
 
PDF
Julia Furst Morgado The Lazy Guide to Kubernetes with EKS Auto Mode + Karpenter
AWS Chicago
 
PDF
NewMind AI Journal - Weekly Chronicles - July'25 Week II
NewMind AI
 
PPTX
TYPES OF COMMUNICATION Presentation of ICT
JulieBinwag
 
PDF
Market Insight : ETH Dominance Returns
CIFDAQ
 
PDF
Market Wrap for 18th July 2025 by CIFDAQ
CIFDAQ
 
PDF
Trading Volume Explained by CIFDAQ- Secret Of Market Trends
CIFDAQ
 
PPTX
Darren Mills The Migration Modernization Balancing Act: Navigating Risks and...
AWS Chicago
 
PPTX
UI5Con 2025 - Beyond UI5 Controls with the Rise of Web Components
Wouter Lemaire
 
PPTX
Extensions Framework (XaaS) - Enabling Orchestrate Anything
ShapeBlue
 
PDF
2025-07-15 EMEA Volledig Inzicht Dutch Webinar
ThousandEyes
 
PDF
Lecture A - AI Workflows for Banking.pdf
Dr. LAM Yat-fai (林日辉)
 
PPTX
python advanced data structure dictionary with examples python advanced data ...
sprasanna11
 
PDF
Meetup Kickoff & Welcome - Rohit Yadav, CSIUG Chairman
ShapeBlue
 
PDF
CIFDAQ Market Insight for 14th July 2025
CIFDAQ
 
PDF
Building Resilience with Digital Twins : Lessons from Korea
SANGHEE SHIN
 
PDF
Apache CloudStack 201: Let's Design & Build an IaaS Cloud
ShapeBlue
 
The Past, Present & Future of Kenya's Digital Transformation
Moses Kemibaro
 
Bitcoin+ Escalando sin concesiones - Parte 1
Fernando Paredes García
 
Empowering Cloud Providers with Apache CloudStack and Stackbill
ShapeBlue
 
"Effect, Fiber & Schema: tactical and technical characteristics of Effect.ts"...
Fwdays
 
Julia Furst Morgado The Lazy Guide to Kubernetes with EKS Auto Mode + Karpenter
AWS Chicago
 
NewMind AI Journal - Weekly Chronicles - July'25 Week II
NewMind AI
 
TYPES OF COMMUNICATION Presentation of ICT
JulieBinwag
 
Market Insight : ETH Dominance Returns
CIFDAQ
 
Market Wrap for 18th July 2025 by CIFDAQ
CIFDAQ
 
Trading Volume Explained by CIFDAQ- Secret Of Market Trends
CIFDAQ
 
Darren Mills The Migration Modernization Balancing Act: Navigating Risks and...
AWS Chicago
 
UI5Con 2025 - Beyond UI5 Controls with the Rise of Web Components
Wouter Lemaire
 
Extensions Framework (XaaS) - Enabling Orchestrate Anything
ShapeBlue
 
2025-07-15 EMEA Volledig Inzicht Dutch Webinar
ThousandEyes
 
Lecture A - AI Workflows for Banking.pdf
Dr. LAM Yat-fai (林日辉)
 
python advanced data structure dictionary with examples python advanced data ...
sprasanna11
 
Meetup Kickoff & Welcome - Rohit Yadav, CSIUG Chairman
ShapeBlue
 
CIFDAQ Market Insight for 14th July 2025
CIFDAQ
 
Building Resilience with Digital Twins : Lessons from Korea
SANGHEE SHIN
 
Apache CloudStack 201: Let's Design & Build an IaaS Cloud
ShapeBlue
 
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