SlideShare ist ein Scribd-Unternehmen logo
1 von 59
Downloaden Sie, um offline zu lesen
SOMETIMES
WEBSOCKETS
DON’T WORK
   @pawel_ledwon
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

Weitere ähnliche Inhalte

Ähnlich wie Sometimes web sockets_dont_work

Secure Mashups
Secure MashupsSecure Mashups
Secure Mashups
kriszyp
 
HTML5 vs Silverlight
HTML5 vs SilverlightHTML5 vs Silverlight
HTML5 vs Silverlight
Matt Casto
 
Meder Kydyraliev - Mining Mach Services within OS X Sandbox
Meder Kydyraliev - Mining Mach Services within OS X SandboxMeder Kydyraliev - Mining Mach Services within OS X Sandbox
Meder Kydyraliev - Mining Mach Services within OS X Sandbox
DefconRussia
 
Service-Oriented Integration With Apache ServiceMix
Service-Oriented Integration With Apache ServiceMixService-Oriented Integration With Apache ServiceMix
Service-Oriented Integration With Apache ServiceMix
Bruce Snyder
 

Ähnlich wie Sometimes web sockets_dont_work (20)

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

Kürzlich hochgeladen

Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
Joaquim Jorge
 

Kürzlich hochgeladen (20)

TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CV
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of Terraform
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 

Sometimes web sockets_dont_work

  • 2.
  • 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