anycable 0.5.0 → 0.5.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.rubocop.yml +6 -0
- data/.travis.yml +4 -4
- data/CHANGELOG.md +14 -2
- data/Gemfile +0 -2
- data/README.md +27 -3
- data/anycable.gemspec +1 -1
- data/benchmarks/2017-02-12.md +54 -57
- data/benchmarks/2018-03-04.md +192 -0
- data/benchmarks/2018-05-27-rpc-bench.md +57 -0
- data/benchmarks/HowTo.md +1 -1
- data/benchmarks/benchmark.yml +35 -8
- data/benchmarks/hosts +2 -2
- data/benchmarks/servers.yml +11 -4
- data/etc/bug_report_template.rb +76 -0
- data/lib/anycable.rb +2 -1
- data/lib/anycable/config.rb +6 -1
- data/lib/anycable/health_server.rb +46 -0
- data/lib/anycable/rpc_handler.rb +4 -4
- data/lib/anycable/server.rb +18 -3
- data/lib/anycable/version.rb +1 -1
- metadata +11 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: '079d557557d69550f4a490d8fcbcd35b922df102af44c076ea14bc92bff5dda3'
|
4
|
+
data.tar.gz: 29339983ff86ec5f52959397b566926c00d7116fa8dd56dc4933bac4bd526689
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a4fdb1f8ccbb3c633996c4aae85ce60263ab5c8f68f13909d93ef2ebe390e5124901b2832221b7fdd809fef1e3ae04628e4e5437aa6f262da51248041b5d0030
|
7
|
+
data.tar.gz: ba3d770e79aa4775e894d2f568787f62d96f1e699828549e0dba1880a85597e01e565fe0781a51b1da42f7cd359cc7580846c7c01f297ee498e4cbfacfba8329
|
data/.rubocop.yml
CHANGED
@@ -22,6 +22,9 @@ AllCops:
|
|
22
22
|
Naming/AccessorMethodName:
|
23
23
|
Enabled: false
|
24
24
|
|
25
|
+
Naming/UncommunicativeMethodParamName:
|
26
|
+
Enabled: false
|
27
|
+
|
25
28
|
Style/PercentLiteralDelimiters:
|
26
29
|
Enabled: false
|
27
30
|
|
@@ -45,6 +48,9 @@ Style/BlockDelimiters:
|
|
45
48
|
Lint/AmbiguousRegexpLiteral:
|
46
49
|
Enabled: false
|
47
50
|
|
51
|
+
Lint/MissingCopEnableDirective:
|
52
|
+
Enabled: false
|
53
|
+
|
48
54
|
Metrics/MethodLength:
|
49
55
|
Exclude:
|
50
56
|
- 'spec/**/*.rb'
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,8 +1,18 @@
|
|
1
1
|
# Change log
|
2
2
|
|
3
|
-
##
|
3
|
+
## master
|
4
4
|
|
5
|
-
|
5
|
+
## 0.5.2 (2018-09-06)
|
6
|
+
|
7
|
+
- [#48](https://github.com/anycable/anycable/pull/48) Add HTTP health server ([@DarthSim][])
|
8
|
+
|
9
|
+
## 0.5.1 (2018-06-13)
|
10
|
+
|
11
|
+
Minor fixes.
|
12
|
+
|
13
|
+
## 0.5.0 (2017-10-21)
|
14
|
+
|
15
|
+
- [#2](https://github.com/anycable/anycable/issues/2) Add support for [Redis Sentinel](https://redis.io/topics/sentinel). ([@accessd][])
|
6
16
|
|
7
17
|
- [#28](https://github.com/anycable/anycable/issues/28) Support arbitrary headers. ([@palkan][])
|
8
18
|
|
@@ -85,3 +95,5 @@ Implement `Disconnect` handler, which invokes `Connection#disconnect` (along wit
|
|
85
95
|
|
86
96
|
[@palkan]: https://github.com/palkan
|
87
97
|
[@sadovnik]: https://github.com/sadovnik
|
98
|
+
[@accessd]: https://github.com/accessd
|
99
|
+
[@DarthSim]: https://github.com/DarthSim
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
[![GitPitch](https://gitpitch.com/assets/badge.svg)](https://gitpitch.com/anycable/anycable/master?grs=github) [![Gem Version](https://badge.fury.io/rb/anycable.svg)](https://rubygems.org/gems/anycable) [![Build Status](https://travis-ci.org/anycable/anycable.svg?branch=master)](https://travis-ci.org/anycable/anycable) [![Circle CI](https://circleci.com/gh/anycable/anycable/tree/master.svg?style=svg)](https://circleci.com/gh/anycable/anycable/tree/master)
|
2
|
-
[![Dependency Status](https://dependencyci.com/github/anycable/anycable/badge)](https://dependencyci.com/github/anycable/anycable)
|
3
2
|
[![Gitter](https://img.shields.io/badge/gitter-join%20chat%20%E2%86%92-brightgreen.svg)](https://gitter.im/anycable/Lobby)
|
4
3
|
|
5
4
|
# Anycable
|
@@ -16,9 +15,21 @@ Rails plug-n-play integration has been extracted to [anycable-rails](https://git
|
|
16
15
|
|
17
16
|
## Requirements
|
18
17
|
|
19
|
-
- Ruby
|
18
|
+
- Ruby >= 2.3, <= 2.5
|
20
19
|
- Redis (for brodcasting, [discuss other options](https://github.com/anycable/anycable/issues/2) with us!)
|
21
20
|
|
21
|
+
Or you can try to [build it from source](https://github.com/grpc/grpc/blob/master/INSTALL.md#build-from-source).
|
22
|
+
|
23
|
+
For MacOS there is also [the same problem](https://github.com/google/protobuf/issues/4098) with `google-protobuf` that can be solved
|
24
|
+
the following way:
|
25
|
+
|
26
|
+
```ruby
|
27
|
+
# Gemfile
|
28
|
+
git 'https://github.com/google/protobuf' do
|
29
|
+
gem 'google-protobuf'
|
30
|
+
end
|
31
|
+
```
|
32
|
+
|
22
33
|
## How It Works?
|
23
34
|
|
24
35
|
![](https://s3.amazonaws.com/anycable/Scheme.png)
|
@@ -29,7 +40,17 @@ Read our [Wiki](https://github.com/anycable/anycable/wiki) for more.
|
|
29
40
|
|
30
41
|
- [AnyCable: Action Cable on steroids!](https://evilmartians.com/chronicles/anycable-actioncable-on-steroids)
|
31
42
|
|
32
|
-
- [Connecting LiteCable to Hanami](http://gabrielmalakias.com.br/ruby/hanami/iot/2017/05/26/websockets-connecting-litecable-to-hanami.html)
|
43
|
+
- [Connecting LiteCable to Hanami](http://gabrielmalakias.com.br/ruby/hanami/iot/2017/05/26/websockets-connecting-litecable-to-hanami.html) by [@GabrielMalakias](https://github.com/GabrielMalakias)
|
44
|
+
|
45
|
+
- [From Action to Any](https://medium.com/@leshchuk/from-action-to-any-1e8d863dd4cf) by [@alekseyl](https://github.com/alekseyl)
|
46
|
+
|
47
|
+
## Talks
|
48
|
+
|
49
|
+
- One cable to rule them all, RubyKaigi 2018, [slides](https://speakerdeck.com/palkan/rubykaigi-2018-anycable-one-cable-to-rule-them-all) and [video](https://www.youtube.com/watch?v=jXCPuNICT8s) (EN)
|
50
|
+
|
51
|
+
- Wroc_Love.rb 2018 [slides](https://speakerdeck.com/palkan/wroc-love-dot-rb-2018-cables-cables-cables) and [video](https://www.youtube.com/watch?v=AUxFFOehiy0) (EN)
|
52
|
+
|
53
|
+
- RubyConfMY 2017 [slides](https://speakerdeck.com/palkan/rubyconf-malaysia-2017-anycable) and [video](https://www.youtube.com/watch?v=j5oFx525zNw) (EN)
|
33
54
|
|
34
55
|
- RailsClub Moscow 2016 [slides](https://speakerdeck.com/palkan/railsclub-moscow-2016-anycable) and [video](https://www.youtube.com/watch?v=-k7GQKuBevY&list=PLiWUIs1hSNeOXZhotgDX7Y7qBsr24cu7o&index=4) (RU)
|
35
56
|
|
@@ -71,6 +92,7 @@ Performing Channel Actions | +
|
|
71
92
|
Streaming | +
|
72
93
|
[Custom stream callbacks](http://edgeapi.rubyonrails.org/classes/ActionCable/Channel/Streams.html) | -
|
73
94
|
Broadcasting | +
|
95
|
+
Custom pubsub adapter | Only redis
|
74
96
|
|
75
97
|
## Build
|
76
98
|
|
@@ -91,5 +113,7 @@ make
|
|
91
113
|
|
92
114
|
Bug reports and pull requests are welcome on GitHub at https://github.com/anycable/anycable.
|
93
115
|
|
116
|
+
Please, provide reproduction script (using [this template](https://github.com/anycable/anycable/blob/master/etc/bug_report_template.rb)) when submitting bugs if possible.
|
117
|
+
|
94
118
|
## License
|
95
119
|
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
data/anycable.gemspec
CHANGED
@@ -26,7 +26,7 @@ Gem::Specification.new do |spec|
|
|
26
26
|
spec.add_development_dependency "rake", ">= 10.0"
|
27
27
|
spec.add_development_dependency "rack", "~> 2.0"
|
28
28
|
spec.add_development_dependency "rspec", ">= 3.5"
|
29
|
-
spec.add_development_dependency "rubocop", "
|
29
|
+
spec.add_development_dependency "rubocop", "~> 0.58.0"
|
30
30
|
spec.add_development_dependency "simplecov", ">= 0.3.8"
|
31
31
|
spec.add_development_dependency "pry-byebug"
|
32
32
|
end
|
data/benchmarks/2017-02-12.md
CHANGED
@@ -3,17 +3,18 @@
|
|
3
3
|
Code: https://github.com/palkan/websocket-shootout
|
4
4
|
Client/Server instances: c3.4xlarge (16 vCPU, 30 GiB RAM).
|
5
5
|
|
6
|
+
Ruby: 2.3.4
|
7
|
+
Rails: 5.1.0
|
8
|
+
|
6
9
|
The benchmark measures broadcasting RTT for 10k clients.
|
7
10
|
|
8
|
-
**NOTE**: memory
|
11
|
+
**NOTE**: memory and CPU usage was measured by looking at `htop` output.
|
9
12
|
|
10
13
|
## Action Cable (8 workers)
|
11
14
|
|
12
15
|
```
|
13
|
-
|
14
|
-
|
15
|
-
00 --payload-padding 200 --total-steps 10 --origin http://0.0.0.0 ws://172.31.22.121:333
|
16
|
-
4/cable --server-type=actioncable
|
16
|
+
bin/websocket-bench broadcast -l 172.31.26.145 -l 172.31.26.146 -l 172.31.26.147 --concurrent 4 --sample-size 100 --step-size 1000 --payload-padding 200 --total-steps 10 --origin http://0.0.0.0 ws://172.31.22.121:3334/cable --server-type=actioncable
|
17
|
+
|
17
18
|
clients: 1000 95per-rtt: 700ms min-rtt: 2ms median-rtt: 264ms max-rtt: 854ms
|
18
19
|
clients: 2000 95per-rtt: 1155ms min-rtt: 1ms median-rtt: 490ms max-rtt: 1358ms
|
19
20
|
clients: 3000 95per-rtt: 1584ms min-rtt: 1ms median-rtt: 769ms max-rtt: 1644ms
|
@@ -24,7 +25,8 @@ clients: 7000 95per-rtt: 3907ms min-rtt: 1ms median-rtt: 1734ms m
|
|
24
25
|
clients: 8000 95per-rtt: 4479ms min-rtt: 1ms median-rtt: 2137ms max-rtt: 5469ms
|
25
26
|
clients: 9000 95per-rtt: 5734ms min-rtt: 1ms median-rtt: 2356ms max-rtt: 8234ms
|
26
27
|
clients: 10000 95per-rtt: 5292ms min-rtt: 1ms median-rtt: 2784ms max-rtt: 6454ms
|
27
|
-
|
28
|
+
|
29
|
+
Missing received broadcasts: expected 6600000, got 6572168
|
28
30
|
```
|
29
31
|
|
30
32
|
CPU: ~70%
|
@@ -34,10 +36,8 @@ MEM: ~ 4 GiB
|
|
34
36
|
## Action Cable (16 workers)
|
35
37
|
|
36
38
|
```
|
37
|
-
|
38
|
-
|
39
|
-
00 --payload-padding 200 --total-steps 10 --origin http://0.0.0.0 ws://172.31.22.121:333
|
40
|
-
4/cable --server-type=actioncable
|
39
|
+
bin/websocket-bench broadcast -l 172.31.26.145 -l 172.31.26.146 -l 172.31.26.147 --concurrent 4 --sample-size 100 --step-size 1000 --payload-padding 200 --total-steps 10 --origin http://0.0.0.0 ws://172.31.22.121:3334/cable --server-type=actioncable
|
40
|
+
|
41
41
|
clients: 1000 95per-rtt: 575ms min-rtt: 1ms median-rtt: 115ms max-rtt: 846ms
|
42
42
|
clients: 2000 95per-rtt: 1144ms min-rtt: 1ms median-rtt: 250ms max-rtt: 1457ms
|
43
43
|
clients: 3000 95per-rtt: 1274ms min-rtt: 1ms median-rtt: 439ms max-rtt: 1673ms
|
@@ -48,7 +48,8 @@ clients: 7000 95per-rtt: 3033ms min-rtt: 1ms median-rtt: 1008ms m
|
|
48
48
|
clients: 8000 95per-rtt: 3275ms min-rtt: 1ms median-rtt: 1160ms max-rtt: 4268ms
|
49
49
|
clients: 9000 95per-rtt: 4406ms min-rtt: 1ms median-rtt: 1342ms max-rtt: 5018ms
|
50
50
|
clients: 10000 95per-rtt: 5414ms min-rtt: 1ms median-rtt: 1504ms max-rtt: 7039ms
|
51
|
-
|
51
|
+
|
52
|
+
Missing received broadcasts: expected 6600000, got 6589644
|
52
53
|
```
|
53
54
|
|
54
55
|
CPU: ~80-100%
|
@@ -60,10 +61,8 @@ MEM: ~ 5 GiB
|
|
60
61
|
About patch: https://github.com/rails/rails/issues/26999
|
61
62
|
|
62
63
|
```
|
63
|
-
|
64
|
-
|
65
|
-
ad-padding 200 --total-steps 10 --origin http://0.0.0.0 ws://172.31.22.121:3334/cable --serve
|
66
|
-
r-type=actioncable
|
64
|
+
bin/websocket-bench broadcast -l 172.31.26.145 -l 172.31.26.146 -l 172.31.26.147 --concurrent 4 --sample-size 100 --step-size 1000 --payload-padding 200 --total-steps 10 --origin http://0.0.0.0 ws://172.31.22.121:3334/cable --server-type=actioncable
|
65
|
+
|
67
66
|
clients: 1000 95per-rtt: 161ms min-rtt: 1ms median-rtt: 44ms max-rtt: 236ms
|
68
67
|
clients: 2000 95per-rtt: 292ms min-rtt: 1ms median-rtt: 43ms max-rtt: 389ms
|
69
68
|
clients: 3000 95per-rtt: 359ms min-rtt: 1ms median-rtt: 96ms max-rtt: 556ms
|
@@ -74,7 +73,8 @@ clients: 7000 95per-rtt: 717ms min-rtt: 1ms median-rtt: 95ms max
|
|
74
73
|
clients: 8000 95per-rtt: 679ms min-rtt: 1ms median-rtt: 19ms max-rtt: 1089ms
|
75
74
|
clients: 9000 95per-rtt: 561ms min-rtt: 1ms median-rtt: 25ms max-rtt: 938ms
|
76
75
|
clients: 10000 95per-rtt: 1038ms min-rtt: 1ms median-rtt: 59ms max-rtt: 2197ms
|
77
|
-
|
76
|
+
|
77
|
+
Missing received broadcasts: expected 6600000, got 5649743
|
78
78
|
```
|
79
79
|
|
80
80
|
CPU: ~70%
|
@@ -84,10 +84,8 @@ MEM: ~ 4 GiB
|
|
84
84
|
## ActionCable / Patched (16 workers)
|
85
85
|
|
86
86
|
```
|
87
|
-
|
88
|
-
|
89
|
-
ad-padding 200 --total-steps 10 --origin http://0.0.0.0 ws://172.31.22.121:3334/cable --serve
|
90
|
-
r-type=actioncable
|
87
|
+
bin/websocket-bench broadcast -l 172.31.26.145 -l 172.31.26.146 -l 172.31.26.147 --concurrent 4 --sample-size 100 --step-size 1000 --payload-padding 200 --total-steps 10 --origin http://0.0.0.0 ws://172.31.22.121:3334/cable --server-type=actioncable
|
88
|
+
|
91
89
|
clients: 1000 95per-rtt: 228ms min-rtt: 1ms median-rtt: 53ms max-rtt: 425ms
|
92
90
|
clients: 2000 95per-rtt: 277ms min-rtt: 1ms median-rtt: 63ms max-rtt: 407ms
|
93
91
|
clients: 3000 95per-rtt: 349ms min-rtt: 1ms median-rtt: 28ms max-rtt: 640ms
|
@@ -98,7 +96,8 @@ clients: 7000 95per-rtt: 466ms min-rtt: 1ms median-rtt: 90ms max
|
|
98
96
|
clients: 8000 95per-rtt: 530ms min-rtt: 1ms median-rtt: 26ms max-rtt: 1225ms
|
99
97
|
clients: 9000 95per-rtt: 459ms min-rtt: 1ms median-rtt: 39ms max-rtt: 622ms
|
100
98
|
clients: 10000 95per-rtt: 477ms min-rtt: 1ms median-rtt: 71ms max-rtt: 632ms
|
101
|
-
|
99
|
+
|
100
|
+
Missing received broadcasts: expected 6600000, got 5662008
|
102
101
|
```
|
103
102
|
|
104
103
|
CPU: ~80-100%
|
@@ -108,10 +107,8 @@ MEM: ~ 5 GiB
|
|
108
107
|
## Action Cable / AnyCable-Go
|
109
108
|
|
110
109
|
```
|
111
|
-
|
112
|
-
|
113
|
-
ad-padding 200 --total-steps 10 --origin http://0.0.0.0 ws://172.31.22.121:3334/cable --serve
|
114
|
-
r-type=actioncable
|
110
|
+
bin/websocket-bench broadcast -l 172.31.26.145 -l 172.31.26.146 -l 172.31.26.147 --concurrent 4 --sample-size 100 --step-size 1000 --payload-padding 200 --total-steps 10 --origin http://0.0.0.0 ws://172.31.22.121:3334/cable --server-type=actioncable
|
111
|
+
|
115
112
|
clients: 1000 95per-rtt: 172ms min-rtt: 2ms median-rtt: 9ms max-rtt: 220ms
|
116
113
|
clients: 2000 95per-rtt: 228ms min-rtt: 2ms median-rtt: 16ms max-rtt: 498ms
|
117
114
|
clients: 3000 95per-rtt: 367ms min-rtt: 2ms median-rtt: 14ms max-rtt: 798ms
|
@@ -122,7 +119,8 @@ clients: 7000 95per-rtt: 813ms min-rtt: 2ms median-rtt: 40ms max
|
|
122
119
|
clients: 8000 95per-rtt: 657ms min-rtt: 2ms median-rtt: 39ms max-rtt: 2457ms
|
123
120
|
clients: 9000 95per-rtt: 792ms min-rtt: 2ms median-rtt: 117ms max-rtt: 1557ms
|
124
121
|
clients: 10000 95per-rtt: 727ms min-rtt: 2ms median-rtt: 66ms max-rtt: 3391ms
|
125
|
-
|
122
|
+
|
123
|
+
Missing received broadcasts: expected 6600000, got 6588881
|
126
124
|
```
|
127
125
|
|
128
126
|
CPU: 15-25%
|
@@ -132,9 +130,8 @@ MEM: ~500 MiB
|
|
132
130
|
## JavaScript / uWS (clustered)
|
133
131
|
|
134
132
|
```
|
135
|
-
|
136
|
-
|
137
|
-
ad-padding 200 --total-steps 10 --origin http://0.0.0.0 ws://172.31.22.121:3334
|
133
|
+
bin/websocket-bench broadcast -l 172.31.26.145 -l 172.31.26.146 -l 172.31.26.147 --concurrent 4 --sample-size 100 --step-size 1000 --payload-padding 200 --total-steps 10 --origin http://0.0.0.0 ws://172.31.22.121:3334
|
134
|
+
|
138
135
|
clients: 1000 95per-rtt: 207ms min-rtt: 0ms median-rtt: 8ms max-rtt: 611ms
|
139
136
|
clients: 2000 95per-rtt: 393ms min-rtt: 2ms median-rtt: 20ms max-rtt: 750ms
|
140
137
|
clients: 3000 95per-rtt: 425ms min-rtt: 4ms median-rtt: 25ms max-rtt: 1196ms
|
@@ -145,7 +142,8 @@ clients: 7000 95per-rtt: 635ms min-rtt: 6ms median-rtt: 37ms max
|
|
145
142
|
clients: 8000 95per-rtt: 782ms min-rtt: 5ms median-rtt: 142ms max-rtt: 1439ms
|
146
143
|
clients: 9000 95per-rtt: 610ms min-rtt: 7ms median-rtt: 72ms max-rtt: 1552ms
|
147
144
|
clients: 10000 95per-rtt: 1216ms min-rtt: 7ms median-rtt: 91ms max-rtt: 2195ms
|
148
|
-
|
145
|
+
|
146
|
+
Missing received broadcasts: expected 6600000, got 6599571
|
149
147
|
```
|
150
148
|
|
151
149
|
CPU: 7-8%
|
@@ -155,9 +153,8 @@ MEM: ~400 MiB
|
|
155
153
|
## Go / WebSocket
|
156
154
|
|
157
155
|
```
|
158
|
-
|
159
|
-
|
160
|
-
ad-padding 200 --total-steps 10 --origin http://0.0.0.0 ws://172.31.22.121:3334/json
|
156
|
+
bin/websocket-bench broadcast -l 172.31.26.145 -l 172.31.26.146 -l 172.31.26.147 --concurrent 4 --sample-size 100 --step-size 1000 --payload-padding 200 --total-steps 10 --origin http://0.0.0.0 ws://172.31.22.121:3334/json
|
157
|
+
|
161
158
|
clients: 1000 95per-rtt: 27ms min-rtt: 7ms median-rtt: 16ms max-rtt: 44ms
|
162
159
|
clients: 2000 95per-rtt: 193ms min-rtt: 12ms median-rtt: 28ms max-rtt: 235ms
|
163
160
|
clients: 3000 95per-rtt: 231ms min-rtt: 15ms median-rtt: 35ms max-rtt: 433ms
|
@@ -168,7 +165,8 @@ clients: 7000 95per-rtt: 449ms min-rtt: 38ms median-rtt: 74ms max
|
|
168
165
|
clients: 8000 95per-rtt: 539ms min-rtt: 43ms median-rtt: 89ms max-rtt: 1351ms
|
169
166
|
clients: 9000 95per-rtt: 534ms min-rtt: 48ms median-rtt: 96ms max-rtt: 2978ms
|
170
167
|
clients: 10000 95per-rtt: 414ms min-rtt: 57ms median-rtt: 123ms max-rtt: 3424ms
|
171
|
-
|
168
|
+
|
169
|
+
Missing received broadcasts: expected 6600000, got 6593825
|
172
170
|
```
|
173
171
|
|
174
172
|
CPU: one core – ~80-100%, other cores – ~7-10%
|
@@ -178,9 +176,8 @@ MEM: ~400 MiB
|
|
178
176
|
## Erlang / Cowboy
|
179
177
|
|
180
178
|
```
|
181
|
-
|
182
|
-
|
183
|
-
ad-padding 200 --total-steps 10 --origin http://0.0.0.0 ws://172.31.22.121:3334/ws/cable
|
179
|
+
bin/websocket-bench broadcast -l 172.31.26.145 -l 172.31.26.146 -l 172.31.26.147 --concurrent 4 --sample-size 100 --step-size 1000 --payload-padding 200 --total-steps 10 --origin http://0.0.0.0 ws://172.31.22.121:3334/ws/cable
|
180
|
+
|
184
181
|
clients: 1000 95per-rtt: 204ms min-rtt: 2ms median-rtt: 11ms max-rtt: 585ms
|
185
182
|
clients: 2000 95per-rtt: 219ms min-rtt: 3ms median-rtt: 20ms max-rtt: 620ms
|
186
183
|
clients: 3000 95per-rtt: 348ms min-rtt: 6ms median-rtt: 19ms max-rtt: 1447ms
|
@@ -191,7 +188,8 @@ clients: 7000 95per-rtt: 542ms min-rtt: 13ms median-rtt: 76ms max
|
|
191
188
|
clients: 8000 95per-rtt: 737ms min-rtt: 16ms median-rtt: 57ms max-rtt: 1527ms
|
192
189
|
clients: 9000 95per-rtt: 634ms min-rtt: 17ms median-rtt: 74ms max-rtt: 1479ms
|
193
190
|
clients: 10000 95per-rtt: 792ms min-rtt: 17ms median-rtt: 79ms max-rtt: 3805ms
|
194
|
-
|
191
|
+
|
192
|
+
Missing received broadcasts: expected 6600000, got 6575292
|
195
193
|
```
|
196
194
|
|
197
195
|
cCPU: 20-30%
|
@@ -201,9 +199,8 @@ MEM: ~500 MiB
|
|
201
199
|
## Ruby / Plezi (1x8)
|
202
200
|
|
203
201
|
```
|
204
|
-
|
205
|
-
|
206
|
-
ad-padding 200 --total-steps 10 --origin http://0.0.0.0 ws://172.31.22.121:3334/
|
202
|
+
bin/websocket-bench broadcast -l 172.31.26.145 -l 172.31.26.146 -l 172.31.26.147 --concurrent 4 --sample-size 100 --step-size 1000 --payload-padding 200 --total-steps 10 --origin http://0.0.0.0 ws://172.31.22.121:3334/
|
203
|
+
|
207
204
|
clients: 1000 95per-rtt: 84ms min-rtt: 3ms median-rtt: 42ms max-rtt: 95ms
|
208
205
|
clients: 2000 95per-rtt: 211ms min-rtt: 4ms median-rtt: 60ms max-rtt: 318ms
|
209
206
|
clients: 3000 95per-rtt: 525ms min-rtt: 2ms median-rtt: 93ms max-rtt: 527ms
|
@@ -214,7 +211,8 @@ clients: 7000 95per-rtt: 1100ms min-rtt: 1ms median-rtt: 249ms ma
|
|
214
211
|
clients: 8000 95per-rtt: 1094ms min-rtt: 7ms median-rtt: 298ms max-rtt: 1134ms
|
215
212
|
clients: 9000 95per-rtt: 1265ms min-rtt: 1ms median-rtt: 342ms max-rtt: 1407ms
|
216
213
|
clients: 10000 95per-rtt: 1523ms min-rtt: 2ms median-rtt: 388ms max-rtt: 1555ms
|
217
|
-
|
214
|
+
|
215
|
+
Missing received broadcasts: expected 6600000, got 6599226
|
218
216
|
```
|
219
217
|
|
220
218
|
CPU: ~10-15% (only 1/2 of cores affected)
|
@@ -224,9 +222,8 @@ MEM: ~300 MiB
|
|
224
222
|
## Ruby / Plezi (8x8)
|
225
223
|
|
226
224
|
```
|
227
|
-
|
228
|
-
|
229
|
-
ad-padding 200 --total-steps 10 --origin http://0.0.0.0 ws://172.31.22.121:3334/
|
225
|
+
bin/websocket-bench broadcast -l 172.31.26.145 -l 172.31.26.146 -l 172.31.26.147 --concurrent 4 --sample-size 100 --step-size 1000 --payload-padding 200 --total-steps 10 --origin http://0.0.0.0 ws://172.31.22.121:3334/
|
226
|
+
|
230
227
|
clients: 1000 95per-rtt: 46ms min-rtt: 1ms median-rtt: 8ms max-rtt: 115ms
|
231
228
|
clients: 2000 95per-rtt: 152ms min-rtt: 1ms median-rtt: 17ms max-rtt: 241ms
|
232
229
|
clients: 3000 95per-rtt: 207ms min-rtt: 1ms median-rtt: 26ms max-rtt: 254ms
|
@@ -237,7 +234,8 @@ clients: 7000 95per-rtt: 210ms min-rtt: 1ms median-rtt: 59ms max
|
|
237
234
|
clients: 8000 95per-rtt: 498ms min-rtt: 2ms median-rtt: 58ms max-rtt: 749ms
|
238
235
|
clients: 9000 95per-rtt: 651ms min-rtt: 2ms median-rtt: 52ms max-rtt: 766ms
|
239
236
|
clients: 10000 95per-rtt: 796ms min-rtt: 1ms median-rtt: 90ms max-rtt: 800ms
|
240
|
-
|
237
|
+
|
238
|
+
Missing received broadcasts: expected 6600000, got 2736158
|
241
239
|
```
|
242
240
|
|
243
241
|
CPU: ~10%
|
@@ -253,9 +251,8 @@ EM shows great results but only for the first run (`em-websocket` bug?).
|
|
253
251
|
First run:
|
254
252
|
|
255
253
|
```
|
256
|
-
|
257
|
-
|
258
|
-
ad-padding 200 --total-steps 10 --origin http://0.0.0.0 ws://172.31.22.121:3334/
|
254
|
+
bin/websocket-bench broadcast -l 172.31.26.145 -l 172.31.26.146 -l 172.31.26.147 --concurrent 4 --sample-size 100 --step-size 1000 --payload-padding 200 --total-steps 10 --origin http://0.0.0.0 ws://172.31.22.121:3334/
|
255
|
+
|
259
256
|
clients: 1000 95per-rtt: 24ms min-rtt: 5ms median-rtt: 20ms max-rtt: 30ms
|
260
257
|
clients: 2000 95per-rtt: 61ms min-rtt: 13ms median-rtt: 42ms max-rtt: 73ms
|
261
258
|
clients: 3000 95per-rtt: 84ms min-rtt: 18ms median-rtt: 68ms max-rtt: 109ms
|
@@ -266,15 +263,15 @@ clients: 7000 95per-rtt: 308ms min-rtt: 43ms median-rtt: 190ms max
|
|
266
263
|
clients: 8000 95per-rtt: 383ms min-rtt: 52ms median-rtt: 218ms max-rtt: 458ms
|
267
264
|
clients: 9000 95per-rtt: 401ms min-rtt: 50ms median-rtt: 218ms max-rtt: 550ms
|
268
265
|
clients: 10000 95per-rtt: 429ms min-rtt: 60ms median-rtt: 246ms max-rtt: 530ms
|
269
|
-
|
266
|
+
|
267
|
+
Missing received broadcasts: expected 6600000, got 6599593
|
270
268
|
```
|
271
269
|
|
272
270
|
Second run:
|
273
271
|
|
274
272
|
```
|
275
|
-
|
276
|
-
|
277
|
-
ad-padding 200 --total-steps 10 --origin http://0.0.0.0 ws://172.31.22.121:3334/
|
273
|
+
bin/websocket-bench broadcast -l 172.31.26.145 -l 172.31.26.146 -l 172.31.26.147 --concurrent 4 --sample-size 100 --step-size 1000 --payload-padding 200 --total-steps 10 --origin http://0.0.0.0 ws://172.31.22.121:3334/
|
274
|
+
|
278
275
|
clients: 1000 95per-rtt: 246ms min-rtt: 47ms median-rtt: 197ms max-rtt: 287ms
|
279
276
|
clients: 2000 95per-rtt: 296ms min-rtt: 63ms median-rtt: 229ms max-rtt: 400ms
|
280
277
|
clients: 3000 95per-rtt: 325ms min-rtt: 184ms median-rtt: 261ms max-rtt: 335ms
|
@@ -290,9 +287,8 @@ clients: 10000 95per-rtt: 813ms min-rtt: 101ms median-rtt: 448ms max
|
|
290
287
|
Third run:
|
291
288
|
|
292
289
|
```
|
293
|
-
|
294
|
-
|
295
|
-
ad-padding 200 --total-steps 10 --origin http://0.0.0.0 ws://172.31.22.121:3334/
|
290
|
+
bin/websocket-bench broadcast -l 172.31.26.145 -l 172.31.26.146 -l 172.31.26.147 --concurrent 4 --sample-size 100 --step-size 1000 --payload-padding 200 --total-steps 10 --origin http://0.0.0.0 ws://172.31.22.121:3334/
|
291
|
+
|
296
292
|
clients: 1000 95per-rtt: 522ms min-rtt: 115ms median-rtt: 414ms max-rtt: 719ms
|
297
293
|
clients: 2000 95per-rtt: 558ms min-rtt: 119ms median-rtt: 444ms max-rtt: 763ms
|
298
294
|
clients: 3000 95per-rtt: 499ms min-rtt: 127ms median-rtt: 489ms max-rtt: 833ms
|
@@ -303,7 +299,8 @@ clients: 7000 95per-rtt: 960ms min-rtt: 130ms median-rtt: 571ms max
|
|
303
299
|
clients: 8000 95per-rtt: 1038ms min-rtt: 145ms median-rtt: 592ms max-rtt: 1179ms
|
304
300
|
clients: 9000 95per-rtt: 1110ms min-rtt: 140ms median-rtt: 625ms max-rtt: 1405ms
|
305
301
|
clients: 10000 95per-rtt: 1176ms min-rtt: 163ms median-rtt: 649ms max-rtt: 1633ms
|
306
|
-
|
302
|
+
|
303
|
+
Missing received broadcasts: expected 6600000, got 6599123
|
307
304
|
```
|
308
305
|
|
309
306
|
CPU: one core is totally f**ked up
|
@@ -0,0 +1,192 @@
|
|
1
|
+
# WebSocket Shootout Benchmark (2018-03-04)
|
2
|
+
|
3
|
+
Code: https://github.com/palkan/websocket-shootout
|
4
|
+
Client/Server instances: c3.2xlarge (8 vCPU, 15 GiB RAM).
|
5
|
+
|
6
|
+
Ruby: 2.5.0
|
7
|
+
Rails: 5.1.4
|
8
|
+
|
9
|
+
The benchmark measures broadcasting RTT for 10k clients.
|
10
|
+
|
11
|
+
**NOTE**: memory and peak CPU usage was measured by looking at `htop` output; avg CPU usage is a 1 minute LA.
|
12
|
+
|
13
|
+
## Action Cable (8 workers)
|
14
|
+
|
15
|
+
Command:
|
16
|
+
|
17
|
+
```sh
|
18
|
+
bin/websocket-bench broadcast -l 172.31.26.145 -l 172.31.26.146 -l 172.31.26.147 --concurrent 4 --sample-size 100 --step-size 1000 --payload-padding 200 --total-steps 10 --origin http://0.0.0.0 ws://172.31.22.121:3334/cable --server-type=actioncable
|
19
|
+
|
20
|
+
clients: 1000 95per-rtt: 847ms min-rtt: 1ms median-rtt: 174ms max-rtt: 930ms
|
21
|
+
clients: 2000 95per-rtt: 1611ms min-rtt: 1ms median-rtt: 387ms max-rtt: 1768ms
|
22
|
+
clients: 3000 95per-rtt: 2107ms min-rtt: 1ms median-rtt: 644ms max-rtt: 2601ms
|
23
|
+
clients: 4000 95per-rtt: 2504ms min-rtt: 1ms median-rtt: 899ms max-rtt: 3118ms
|
24
|
+
clients: 5000 95per-rtt: 3452ms min-rtt: 1ms median-rtt: 1070ms max-rtt: 4487ms
|
25
|
+
clients: 6000 95per-rtt: 4044ms min-rtt: 1ms median-rtt: 1261ms max-rtt: 5018ms
|
26
|
+
clients: 7000 95per-rtt: 3207ms min-rtt: 1ms median-rtt: 1647ms max-rtt: 3958ms
|
27
|
+
clients: 8000 95per-rtt: 4115ms min-rtt: 1ms median-rtt: 1957ms max-rtt: 5059ms
|
28
|
+
clients: 9000 95per-rtt: 4306ms min-rtt: 1ms median-rtt: 2273ms max-rtt: 7160ms
|
29
|
+
clients: 10000 95per-rtt: 5147ms min-rtt: 1ms median-rtt: 2462ms max-rtt: 6734ms
|
30
|
+
|
31
|
+
Missing received broadcasts: expected 6600000, got 6554972
|
32
|
+
```
|
33
|
+
|
34
|
+
CPU (peak): ~100%
|
35
|
+
CPU (avg): ~30%
|
36
|
+
|
37
|
+
MEM: ~1.7 GiB
|
38
|
+
|
39
|
+
|
40
|
+
## AnyCable-Go 0.5.4
|
41
|
+
|
42
|
+
```
|
43
|
+
bin/websocket-bench broadcast -l 172.31.26.145 -l 172.31.26.146 -l 172.31.26.147 --concurrent 4 --sample-size 100 --step-size 1000 --payload-padding 200 --total-steps 10 --origin http://0.0.0.0 ws://172.31.22.121:3334/cable --server-type=actioncable
|
44
|
+
|
45
|
+
clients: 1000 95per-rtt: 61ms min-rtt: 2ms median-rtt: 18ms max-rtt: 178ms
|
46
|
+
clients: 2000 95per-rtt: 214ms min-rtt: 2ms median-rtt: 26ms max-rtt: 568ms
|
47
|
+
clients: 3000 95per-rtt: 275ms min-rtt: 2ms median-rtt: 32ms max-rtt: 645ms
|
48
|
+
clients: 4000 95per-rtt: 430ms min-rtt: 2ms median-rtt: 40ms max-rtt: 1463ms
|
49
|
+
clients: 5000 95per-rtt: 352ms min-rtt: 3ms median-rtt: 61ms max-rtt: 1017ms
|
50
|
+
clients: 6000 95per-rtt: 619ms min-rtt: 3ms median-rtt: 60ms max-rtt: 1630ms
|
51
|
+
clients: 7000 95per-rtt: 623ms min-rtt: 2ms median-rtt: 74ms max-rtt: 3099ms
|
52
|
+
clients: 8000 95per-rtt: 846ms min-rtt: 2ms median-rtt: 89ms max-rtt: 3165ms
|
53
|
+
clients: 9000 95per-rtt: 642ms min-rtt: 2ms median-rtt: 110ms max-rtt: 981ms
|
54
|
+
clients: 10000 95per-rtt: 1019ms min-rtt: 2ms median-rtt: 114ms max-rtt: 4759ms
|
55
|
+
|
56
|
+
Missing received broadcasts: expected 6600000, got 6580959
|
57
|
+
```
|
58
|
+
|
59
|
+
CPU (peak): ~40%
|
60
|
+
CPU (avg): ~3%
|
61
|
+
|
62
|
+
MEM: ~500 MiB
|
63
|
+
|
64
|
+
## AnyCable-Go 0.6.0-preview1
|
65
|
+
|
66
|
+
```
|
67
|
+
bin/websocket-bench broadcast -l 172.31.26.145 -l 172.31.26.146 -l 172.31.26.147 --concurrent 4 --sample-size 100 --step-size 1000 --payload-padding 200 --total-steps 10 --origin http://0.0.0.0 ws://172.31.22.121:3334/cable --server-type=actioncable
|
68
|
+
|
69
|
+
clients: 1000 95per-rtt: 64ms min-rtt: 2ms median-rtt: 15ms max-rtt: 191ms
|
70
|
+
clients: 2000 95per-rtt: 188ms min-rtt: 2ms median-rtt: 27ms max-rtt: 325ms
|
71
|
+
clients: 3000 95per-rtt: 218ms min-rtt: 2ms median-rtt: 36ms max-rtt: 854ms
|
72
|
+
clients: 4000 95per-rtt: 483ms min-rtt: 2ms median-rtt: 37ms max-rtt: 2353ms
|
73
|
+
clients: 5000 95per-rtt: 388ms min-rtt: 2ms median-rtt: 63ms max-rtt: 659ms
|
74
|
+
clients: 6000 95per-rtt: 500ms min-rtt: 2ms median-rtt: 59ms max-rtt: 1430ms
|
75
|
+
clients: 7000 95per-rtt: 692ms min-rtt: 2ms median-rtt: 85ms max-rtt: 1333ms
|
76
|
+
clients: 8000 95per-rtt: 591ms min-rtt: 2ms median-rtt: 90ms max-rtt: 2499ms
|
77
|
+
clients: 9000 95per-rtt: 959ms min-rtt: 2ms median-rtt: 90ms max-rtt: 5961ms
|
78
|
+
clients: 10000 95per-rtt: 674ms min-rtt: 2ms median-rtt: 106ms max-rtt: 2543ms
|
79
|
+
|
80
|
+
Missing received broadcasts: expected 6600000, got 6599507
|
81
|
+
```
|
82
|
+
|
83
|
+
CPU (peak): ~40%
|
84
|
+
CPU (avg): ~3%
|
85
|
+
|
86
|
+
MEM: ~450 MiB
|
87
|
+
|
88
|
+
## Plezi (0.15.0) + Iodine (0.4.16) (8 workers)
|
89
|
+
|
90
|
+
```
|
91
|
+
bin/websocket-bench broadcast -l 172.31.26.145 -l 172.31.26.146 -l 172.31.26.147 --concurrent 4 --sample-size 100 --step-size 1000 --payload-padding 200 --total-steps 10 ws://172.31.22.121:3334/cable
|
92
|
+
|
93
|
+
clients: 1000 95per-rtt: 48ms min-rtt: 1ms median-rtt: 18ms max-rtt: 208ms
|
94
|
+
clients: 2000 95per-rtt: 236ms min-rtt: 0ms median-rtt: 24ms max-rtt: 612ms
|
95
|
+
clients: 3000 95per-rtt: 224ms min-rtt: 0ms median-rtt: 38ms max-rtt: 662ms
|
96
|
+
clients: 4000 95per-rtt: 402ms min-rtt: 0ms median-rtt: 39ms max-rtt: 3071ms
|
97
|
+
clients: 5000 95per-rtt: 392ms min-rtt: 1ms median-rtt: 47ms max-rtt: 1850ms
|
98
|
+
clients: 6000 95per-rtt: 582ms min-rtt: 1ms median-rtt: 64ms max-rtt: 1825ms
|
99
|
+
clients: 7000 95per-rtt: 393ms min-rtt: 1ms median-rtt: 92ms max-rtt: 729ms
|
100
|
+
clients: 8000 95per-rtt: 1181ms min-rtt: 1ms median-rtt: 42ms max-rtt: 5782ms
|
101
|
+
clients: 9000 95per-rtt: 676ms min-rtt: 1ms median-rtt: 107ms max-rtt: 2220ms
|
102
|
+
clients: 10000 95per-rtt: 603ms min-rtt: 1ms median-rtt: 131ms max-rtt: 5703ms
|
103
|
+
|
104
|
+
Missing received broadcasts: expected 6600000, got 6586987
|
105
|
+
```
|
106
|
+
|
107
|
+
CPU (peak): ~50%
|
108
|
+
CPU (avg): ~5%
|
109
|
+
|
110
|
+
MEM: ~700 MiB
|
111
|
+
|
112
|
+
*NOTE*: Plezi app is not a Rails app, thus its memory is less than in Rails examples.
|
113
|
+
|
114
|
+
# More Stress
|
115
|
+
|
116
|
+
Peak connections: 20k.
|
117
|
+
Concurrency: 8.
|
118
|
+
|
119
|
+
## Plezi (0.15.0) + Iodine (0.4.16)
|
120
|
+
|
121
|
+
CPU (peak): ~90%
|
122
|
+
CPU (avg): ~6%
|
123
|
+
Mem: ~1100MB
|
124
|
+
|
125
|
+
|
126
|
+
```
|
127
|
+
clients: 1000 95per-rtt: 216ms min-rtt: 1ms median-rtt: 17ms max-rtt: 364ms
|
128
|
+
clients: 2000 95per-rtt: 446ms min-rtt: 0ms median-rtt: 24ms max-rtt: 738ms
|
129
|
+
clients: 3000 95per-rtt: 348ms min-rtt: 0ms median-rtt: 46ms max-rtt: 925ms
|
130
|
+
clients: 4000 95per-rtt: 654ms min-rtt: 2ms median-rtt: 65ms max-rtt: 1175ms
|
131
|
+
clients: 5000 95per-rtt: 590ms min-rtt: 0ms median-rtt: 67ms max-rtt: 1842ms
|
132
|
+
clients: 6000 95per-rtt: 469ms min-rtt: 1ms median-rtt: 121ms max-rtt: 1098ms
|
133
|
+
clients: 7000 95per-rtt: 705ms min-rtt: 1ms median-rtt: 121ms max-rtt: 1617ms
|
134
|
+
clients: 8000 95per-rtt: 1090ms min-rtt: 1ms median-rtt: 159ms max-rtt: 3253ms
|
135
|
+
clients: 9000 95per-rtt: 869ms min-rtt: 1ms median-rtt: 163ms max-rtt: 3945ms
|
136
|
+
clients: 10000 95per-rtt: 1171ms min-rtt: 1ms median-rtt: 247ms max-rtt: 2326ms
|
137
|
+
clients: 11000 95per-rtt: 1634ms min-rtt: 1ms median-rtt: 191ms max-rtt: 4383ms
|
138
|
+
clients: 12000 95per-rtt: 1138ms min-rtt: 2ms median-rtt: 283ms max-rtt: 8319ms
|
139
|
+
clients: 13000 95per-rtt: 1234ms min-rtt: 1ms median-rtt: 306ms max-rtt: 5429ms
|
140
|
+
clients: 14000 95per-rtt: 947ms min-rtt: 1ms median-rtt: 346ms max-rtt: 7804ms
|
141
|
+
clients: 15000 95per-rtt: 1716ms min-rtt: 1ms median-rtt: 344ms max-rtt: 7372ms
|
142
|
+
clients: 16000 95per-rtt: 1999ms min-rtt: 1ms median-rtt: 364ms max-rtt: 3047ms
|
143
|
+
clients: 17000 95per-rtt: 1729ms min-rtt: 1ms median-rtt: 410ms max-rtt: 7231ms
|
144
|
+
clients: 18000 95per-rtt: 1455ms min-rtt: 1ms median-rtt: 442ms max-rtt: 4725ms
|
145
|
+
clients: 19000 95per-rtt: 2006ms min-rtt: 1ms median-rtt: 456ms max-rtt: 3811ms
|
146
|
+
clients: 20000 95per-rtt: 2923ms min-rtt: 1ms median-rtt: 378ms max-rtt: 11954ms
|
147
|
+
|
148
|
+
Missing received broadcasts: expected 23100000, got 23089387
|
149
|
+
```
|
150
|
+
|
151
|
+
## Anycable-Go 0.6.0-preview1
|
152
|
+
|
153
|
+
CPU (peak): ~60%
|
154
|
+
CPU (avg): ~4%
|
155
|
+
Mem: ~1000MB
|
156
|
+
|
157
|
+
```
|
158
|
+
clients: 1000 95per-rtt: 173ms min-rtt: 2ms median-rtt: 21ms max-rtt: 617ms
|
159
|
+
clients: 2000 95per-rtt: 311ms min-rtt: 2ms median-rtt: 39ms max-rtt: 594ms
|
160
|
+
clients: 3000 95per-rtt: 386ms min-rtt: 3ms median-rtt: 91ms max-rtt: 592ms
|
161
|
+
clients: 4000 95per-rtt: 539ms min-rtt: 2ms median-rtt: 93ms max-rtt: 973ms
|
162
|
+
clients: 5000 95per-rtt: 534ms min-rtt: 2ms median-rtt: 128ms max-rtt: 1486ms
|
163
|
+
clients: 6000 95per-rtt: 1092ms min-rtt: 2ms median-rtt: 110ms max-rtt: 3073ms
|
164
|
+
clients: 7000 95per-rtt: 726ms min-rtt: 3ms median-rtt: 185ms max-rtt: 1116ms
|
165
|
+
clients: 8000 95per-rtt: 1078ms min-rtt: 2ms median-rtt: 174ms max-rtt: 3296ms
|
166
|
+
clients: 9000 95per-rtt: 1401ms min-rtt: 8ms median-rtt: 195ms max-rtt: 6838ms
|
167
|
+
clients: 10000 95per-rtt: 1157ms min-rtt: 3ms median-rtt: 282ms max-rtt: 3446ms
|
168
|
+
clients: 11000 95per-rtt: 1804ms min-rtt: 4ms median-rtt: 271ms max-rtt: 5640ms
|
169
|
+
clients: 12000 95per-rtt: 1339ms min-rtt: 2ms median-rtt: 344ms max-rtt: 2251ms
|
170
|
+
clients: 13000 95per-rtt: 1638ms min-rtt: 3ms median-rtt: 336ms max-rtt: 3341ms
|
171
|
+
clients: 14000 95per-rtt: 1811ms min-rtt: 3ms median-rtt: 339ms max-rtt: 2079ms
|
172
|
+
clients: 15000 95per-rtt: 1407ms min-rtt: 2ms median-rtt: 435ms max-rtt: 6666ms
|
173
|
+
clients: 16000 95per-rtt: 2796ms min-rtt: 2ms median-rtt: 398ms max-rtt: 4769ms
|
174
|
+
clients: 17000 95per-rtt: 2494ms min-rtt: 6ms median-rtt: 338ms max-rtt: 36085ms
|
175
|
+
clients: 18000 95per-rtt: 2844ms min-rtt: 2ms median-rtt: 374ms max-rtt: 7384ms
|
176
|
+
clients: 19000 95per-rtt: 4010ms min-rtt: 17ms median-rtt: 370ms max-rtt: 5504ms
|
177
|
+
clients: 20000 95per-rtt: 2819ms min-rtt: 2ms median-rtt: 470ms max-rtt: 8598ms
|
178
|
+
|
179
|
+
Missing received broadcasts: expected 23100000, got 23065521
|
180
|
+
```
|
181
|
+
|
182
|
+
# Idle Connections Benchmark
|
183
|
+
|
184
|
+
Connection 20k idle clients at 200 connections per second rate; measuring final memory usage.
|
185
|
+
|
186
|
+
Using [cable_bench](https://github.com/palkan/cable_bench).
|
187
|
+
|
188
|
+
**Action Cable (8 workers)**: ~1500 MB
|
189
|
+
|
190
|
+
**Anycable-Go 0.6.0-preview1**: ~700 MB
|
191
|
+
|
192
|
+
**Plezi (0.15.0) + Iodine (0.4.16)**: ~800 MB (a lot of connection timeout errors and "The connection was lost" errors).
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# AnyCable RPC benchmarks
|
2
|
+
|
3
|
+
AnyCable RPC server benchmarks.
|
4
|
+
|
5
|
+
The benchmark is pretty simple:
|
6
|
+
- Create N concurrent _clients_ (authenticate and subscribe to `BenchmarkChannel` within the RPC app)
|
7
|
+
- Every client starts performing an action (`echo`) in a loop
|
8
|
+
- Every call is collected (request time)
|
9
|
+
- Wait for the specified amount of seconds and aggragate the results.
|
10
|
+
|
11
|
+
Measuring **requests per seconds**.
|
12
|
+
|
13
|
+
**NOTE:** this benchmark shows performance characteristics for both _clients_ and the server.
|
14
|
+
The purpose of this benchmark is to measure the thoughout of RPC connection between AnyCable services.
|
15
|
+
|
16
|
+
**NOTE 2:** "Noop RPC" is just a gRPC handling doing nothing except from responding with success result.
|
17
|
+
|
18
|
+
Sources:
|
19
|
+
- [Golang](https://github.com/anycable/anycable-go/blob/chore/benchmarking/cmd/rpc-bench/main.go)
|
20
|
+
- [Erlang](https://github.com/anycable/simple-cable-app/tree/master/benchmarks)
|
21
|
+
|
22
|
+
## Erlang single connection
|
23
|
+
|
24
|
+
RPC type \ Number of clients | 1 | 10 | 50
|
25
|
+
--------------------------------|------|------|----
|
26
|
+
AnyCable RPC | 100 | 110 | 130
|
27
|
+
Noop RPC | 100 | 115 | 125
|
28
|
+
|
29
|
+
Erlang client definitely has problems(
|
30
|
+
|
31
|
+
Looks like HTTP2 streaming is working in _blocking mode_.
|
32
|
+
|
33
|
+
Requires investigation.
|
34
|
+
|
35
|
+
## Erlycable connection pool (5-50)
|
36
|
+
|
37
|
+
RPC type \ Number of clients | 1 | 10 | 50
|
38
|
+
--------------------------------|------|------|----
|
39
|
+
AnyCable RPC | 100 | 800 | 1700
|
40
|
+
Noop RPC | 100 | 900 | 2700
|
41
|
+
|
42
|
+
## Golang single connection
|
43
|
+
|
44
|
+
RPC type \ Number of clients | 1 | 10 | 50
|
45
|
+
--------------------------------|------|------|----
|
46
|
+
AnyCable RPC | 1600 | 2200 | 2400
|
47
|
+
Noop RPC with connection object building\* | 2200 | 3500 | 4000
|
48
|
+
Noop RPC | 3000 | 4600 | 5500
|
49
|
+
|
50
|
+
\* Only build Action Cable connection object without performing an action.
|
51
|
+
|
52
|
+
## Golang connection pool (5-50)
|
53
|
+
|
54
|
+
RPC type \ Number of clients | 1 | 10 | 50
|
55
|
+
--------------------------------|------|------|----
|
56
|
+
AnyCable RPC | 1400 | 1500 | 1700
|
57
|
+
Noop RPC | 2100 | 3200 | 4000
|
data/benchmarks/HowTo.md
CHANGED
@@ -10,7 +10,7 @@
|
|
10
10
|
|
11
11
|
- Update `hosts` file and playbooks with required information (IPs, etc)
|
12
12
|
|
13
|
-
- Prepare the _client_ instance: `ansible-playbook --
|
13
|
+
- Prepare the _client_ instance: `ansible-playbook --tags prepare benchmark.yml`
|
14
14
|
|
15
15
|
### Running benchmarks
|
16
16
|
|
data/benchmarks/benchmark.yml
CHANGED
@@ -5,17 +5,19 @@
|
|
5
5
|
remote_user: ubuntu
|
6
6
|
gather_facts: False
|
7
7
|
vars:
|
8
|
-
server_host: '172.31.
|
8
|
+
server_host: '172.31.17.82'
|
9
9
|
hostname: ws-bench-client
|
10
|
-
local_ips: ['172.31.
|
11
|
-
local_ips_str: '-l 172.31.
|
12
|
-
steps:
|
10
|
+
local_ips: ['172.31.17.191', '172.31.17.192', '172.31.17.193', '172.31.17.194']
|
11
|
+
local_ips_str: '-l 172.31.17.191 -l 172.31.17.192 -l 172.31.17.193 -l 172.31.17.194'
|
12
|
+
steps: 20
|
13
13
|
step_size: 1000
|
14
|
-
sample_size:
|
14
|
+
sample_size: 100
|
15
|
+
concurrency: 8
|
16
|
+
payload_size: 200
|
15
17
|
prepare: False
|
16
18
|
tasks:
|
17
19
|
- name: Prepare the machine
|
18
|
-
|
20
|
+
tags: prepare
|
19
21
|
block:
|
20
22
|
- hostname:
|
21
23
|
name: "{{ hostname }}"
|
@@ -25,16 +27,41 @@
|
|
25
27
|
state: present
|
26
28
|
- shell: ip addr add {{ item }}/20 dev eth0
|
27
29
|
with_items: "{{ local_ips }}"
|
30
|
+
|
31
|
+
- name: Print Action Cable command
|
32
|
+
debug: msg="bin/websocket-bench broadcast {{ local_ips_str }} --concurrent {{ concurrency }} --sample-size {{ sample_size }} --step-size {{ step_size }} --payload-padding {{ payload_size }} --total-steps {{ steps }} --origin http://0.0.0.0 ws://{{ server_host }}:3334/cable --server-type=actioncable"
|
33
|
+
tags: action_cable
|
34
|
+
|
28
35
|
- name: Action Cable benchmark
|
29
36
|
become_user: deplo
|
30
|
-
shell: bin/websocket-bench broadcast {{ local_ips_str }} --concurrent
|
37
|
+
shell: bin/websocket-bench broadcast {{ local_ips_str }} --concurrent {{ concurrency }} --sample-size {{ sample_size }} --step-size {{ step_size }} --payload-padding {{ payload_size }} --total-steps {{ steps }} --origin http://0.0.0.0 ws://{{ server_host }}:3334/cable --server-type=actioncable
|
31
38
|
register: bench
|
32
39
|
tags: action_cable
|
33
40
|
args:
|
34
41
|
chdir: /webapps/anycable_bench
|
35
42
|
ignore_errors: yes
|
36
43
|
|
37
|
-
- name:
|
44
|
+
- name: Print Plezi command
|
45
|
+
debug: msg="bin/websocket-bench broadcast {{ local_ips_str }} --concurrent {{ concurrency }} --sample-size {{ sample_size }} --step-size {{ step_size }} --payload-padding {{ payload_size }} --total-steps {{ steps }} ws://{{ server_host }}:3334/cable"
|
46
|
+
tags: plezi
|
47
|
+
|
48
|
+
- name: Plezi benchmark
|
49
|
+
become_user: deplo
|
50
|
+
shell: bin/websocket-bench broadcast {{ local_ips_str }} --concurrent {{ concurrency }} --sample-size {{ sample_size }} --step-size {{ step_size }} --payload-padding {{ payload_size }} --total-steps {{ steps }} ws://{{ server_host }}:3334/cable
|
51
|
+
register: bench
|
52
|
+
tags: plezi
|
53
|
+
args:
|
54
|
+
chdir: /webapps/anycable_bench
|
55
|
+
ignore_errors: yes
|
56
|
+
|
57
|
+
- name: Benchmark results (stdout)
|
38
58
|
debug: var=bench.stdout_lines
|
39
59
|
tags:
|
40
60
|
- action_cable
|
61
|
+
- plezi
|
62
|
+
|
63
|
+
- name: Benchmark results (stderr)
|
64
|
+
debug: var=bench.stderr_lines
|
65
|
+
tags:
|
66
|
+
- action_cable
|
67
|
+
- plezi
|
data/benchmarks/hosts
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
[benchmark]
|
2
|
-
ec2-52-
|
2
|
+
ec2-52-19-57-142.eu-west-1.compute.amazonaws.com ansible_ssh_private_key_file=/Users/palkan/.ssh/macos-dev
|
3
3
|
|
4
4
|
[servers]
|
5
|
-
ec2-
|
5
|
+
ec2-34-252-33-102.eu-west-1.compute.amazonaws.com ansible_ssh_private_key_file=/Users/palkan/.ssh/macos-dev
|
data/benchmarks/servers.yml
CHANGED
@@ -5,25 +5,32 @@
|
|
5
5
|
remote_user: ubuntu
|
6
6
|
gather_facts: False
|
7
7
|
vars:
|
8
|
-
|
8
|
+
web_concurrency: 8
|
9
9
|
tasks:
|
10
10
|
- name: Kill servers
|
11
11
|
shell: pid=$(lsof -i:{{item}} -t); kill -TERM $pid || kill -KILL $pid
|
12
12
|
tags:
|
13
13
|
- action_cable
|
14
14
|
- anycable
|
15
|
+
- plezi
|
15
16
|
with_items:
|
16
17
|
- "3334"
|
17
18
|
ignore_errors: true
|
18
19
|
- name: Run Action Cable
|
19
20
|
become_user: deplo
|
20
21
|
tags: action_cable
|
21
|
-
shell: WEB_CONCURRENCY={{
|
22
|
+
shell: WEB_CONCURRENCY={{ web_concurrency }} bundle exec rails s -p 3334 -e production
|
22
23
|
args:
|
23
24
|
chdir: /webapps/anycable_bench/ruby/action-cable-server
|
24
25
|
- name: Run Anycable Go
|
25
26
|
become_user: deplo
|
26
27
|
tags: anycable
|
27
|
-
shell: bundle exec anycable
|
28
|
+
shell: ANYCABLE_GO_BIN="anycable-go-0.6.0" ANYCABLE_PORT="3334" bundle exec bin/anycable
|
28
29
|
args:
|
29
|
-
chdir: /webapps/anycable_bench/ruby/action-cable-server
|
30
|
+
chdir: /webapps/anycable_bench/ruby/action-cable-server
|
31
|
+
- name: Run Iodine/Plezi
|
32
|
+
become_user: deplo
|
33
|
+
tags: plezi
|
34
|
+
shell: iodine -p 3334
|
35
|
+
args:
|
36
|
+
chdir: /webapps/anycable_bench/ruby/plezi-iodine
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bundler/inline"
|
4
|
+
|
5
|
+
# This reproduction script is based on `anyt` gem
|
6
|
+
# (https://github.com/anycable/anyt).
|
7
|
+
#
|
8
|
+
# See more test examples here:
|
9
|
+
# https://github.com/anycable/anyt/tree/master/lib/anyt/tests
|
10
|
+
|
11
|
+
gemfile(true) do
|
12
|
+
source "https://rubygems.org"
|
13
|
+
|
14
|
+
gem "anyt"
|
15
|
+
end
|
16
|
+
|
17
|
+
require "anyt"
|
18
|
+
require "anyt/cli"
|
19
|
+
require "anycable-rails"
|
20
|
+
|
21
|
+
# WebSocket server url
|
22
|
+
ENV['ANYT_TARGET_URL'] ||= "ws://localhost:8080/cable"
|
23
|
+
|
24
|
+
# Command to launch WebSocket server.
|
25
|
+
# Comment this line if you want to run WebSocket server manually
|
26
|
+
ENV['ANYT_COMMAND'] ||= "anycable-go"
|
27
|
+
|
28
|
+
ActionCable.server.config.logger = Rails.logger = Anycable.logger
|
29
|
+
|
30
|
+
# Test scenario
|
31
|
+
feature "issue_xyz" do
|
32
|
+
# This block defines an anonymous channel to test against
|
33
|
+
channel do
|
34
|
+
# def subscribed
|
35
|
+
# stream_from "a"
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# def perform(data)
|
39
|
+
# # ...
|
40
|
+
# end
|
41
|
+
end
|
42
|
+
|
43
|
+
# You can use minitest/spec features here
|
44
|
+
before do
|
45
|
+
# `channel` contains identifier of the anonymous channel defined above
|
46
|
+
subscribe_request = { command: "subscribe", identifier: { channel: channel }.to_json }
|
47
|
+
|
48
|
+
# `client` represents a websocket client connected to a server
|
49
|
+
client.send(subscribe_request)
|
50
|
+
|
51
|
+
ack = {
|
52
|
+
"identifier" => { channel: channel }.to_json, "type" => "confirm_subscription"
|
53
|
+
}
|
54
|
+
|
55
|
+
# `receive` method returns the first message from the incoming messages queue;
|
56
|
+
# waits 5s when no messages available
|
57
|
+
assert_equal ack, client.receive
|
58
|
+
end
|
59
|
+
|
60
|
+
# describe you bug scenario here
|
61
|
+
scenario %{
|
62
|
+
Should work
|
63
|
+
} do
|
64
|
+
# ...
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Required setup/teardown
|
69
|
+
begin
|
70
|
+
Anyt::RPC.start
|
71
|
+
Anyt::Command.run if Anyt.config.command
|
72
|
+
Anyt::Tests.run
|
73
|
+
ensure
|
74
|
+
Anyt::Command.stop if Anyt.config.command
|
75
|
+
Anyt::RPC.stop
|
76
|
+
end
|
data/lib/anycable.rb
CHANGED
@@ -47,7 +47,8 @@ module Anycable
|
|
47
47
|
@pubsub ||= PubSub.new
|
48
48
|
end
|
49
49
|
|
50
|
-
#
|
50
|
+
# Raw broadcast message to the channel, sends only string!
|
51
|
+
# To send hash or object use ActionCable.server.broadcast instead!
|
51
52
|
def broadcast(channel, payload)
|
52
53
|
pubsub.broadcast(channel, payload)
|
53
54
|
end
|
data/lib/anycable/config.rb
CHANGED
@@ -14,7 +14,8 @@ module Anycable
|
|
14
14
|
log_file: nil,
|
15
15
|
log_level: :info,
|
16
16
|
log_grpc: false,
|
17
|
-
debug: false # Shortcut to enable GRPC logging and debug level
|
17
|
+
debug: false, # Shortcut to enable GRPC logging and debug level
|
18
|
+
http_health_port: nil
|
18
19
|
|
19
20
|
def initialize(*)
|
20
21
|
super
|
@@ -23,5 +24,9 @@ module Anycable
|
|
23
24
|
self.log_level = :debug
|
24
25
|
self.log_grpc = true
|
25
26
|
end
|
27
|
+
|
28
|
+
def http_health_port_provided?
|
29
|
+
!http_health_port.nil? && http_health_port != ""
|
30
|
+
end
|
26
31
|
end
|
27
32
|
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'webrick'
|
4
|
+
require 'anycable/server'
|
5
|
+
|
6
|
+
module Anycable
|
7
|
+
# Server for HTTP healthchecks
|
8
|
+
module HealthServer
|
9
|
+
class << self
|
10
|
+
def start(port)
|
11
|
+
return if running?
|
12
|
+
|
13
|
+
@health_server ||= build_server(port)
|
14
|
+
Thread.new { @health_server.start }
|
15
|
+
|
16
|
+
Anycable.logger.info "HTTP health server is listening on #{port}"
|
17
|
+
end
|
18
|
+
|
19
|
+
def stop
|
20
|
+
return unless running?
|
21
|
+
@health_server.shutdown
|
22
|
+
end
|
23
|
+
|
24
|
+
def running?
|
25
|
+
@health_server&.status == :Running
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
SUCCESS_RESPONSE = [200, "Ready"].freeze
|
31
|
+
FAILURE_RESPONSE = [503, "Not Ready"].freeze
|
32
|
+
|
33
|
+
def build_server(port)
|
34
|
+
WEBrick::HTTPServer.new(
|
35
|
+
Port: port,
|
36
|
+
Logger: Anycable.logger,
|
37
|
+
AccessLog: []
|
38
|
+
).tap do |server|
|
39
|
+
server.mount_proc '/health' do |_, res|
|
40
|
+
res.status, res.body = Anycable::Server.running? ? SUCCESS_RESPONSE : FAILURE_RESPONSE
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
data/lib/anycable/rpc_handler.rb
CHANGED
@@ -15,7 +15,7 @@ module Anycable
|
|
15
15
|
|
16
16
|
# Handle connection request from WebSocket server
|
17
17
|
def connect(request, _unused_call)
|
18
|
-
logger.debug("RPC Connect: #{request}")
|
18
|
+
logger.debug("RPC Connect: #{request.inspect}")
|
19
19
|
|
20
20
|
socket = build_socket(env: rack_env(request))
|
21
21
|
|
@@ -35,7 +35,7 @@ module Anycable
|
|
35
35
|
end
|
36
36
|
|
37
37
|
def disconnect(request, _unused_call)
|
38
|
-
logger.debug("RPC
|
38
|
+
logger.debug("RPC Disconnect: #{request.inspect}")
|
39
39
|
|
40
40
|
socket = build_socket(env: rack_env(request))
|
41
41
|
|
@@ -53,7 +53,7 @@ module Anycable
|
|
53
53
|
end
|
54
54
|
|
55
55
|
def command(message, _unused_call)
|
56
|
-
logger.debug("RPC Command: #{message}")
|
56
|
+
logger.debug("RPC Command: #{message.inspect}")
|
57
57
|
|
58
58
|
socket = build_socket
|
59
59
|
|
@@ -96,7 +96,7 @@ module Anycable
|
|
96
96
|
end
|
97
97
|
|
98
98
|
def build_socket(**options)
|
99
|
-
Anycable::Socket.new(
|
99
|
+
Anycable::Socket.new(options)
|
100
100
|
end
|
101
101
|
|
102
102
|
def build_headers(headers)
|
data/lib/anycable/server.rb
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require 'grpc'
|
4
4
|
require 'anycable/rpc_handler'
|
5
|
+
require 'anycable/health_server'
|
5
6
|
|
6
7
|
module Anycable
|
7
8
|
# Wrapper over GRPC server
|
@@ -11,10 +12,9 @@ module Anycable
|
|
11
12
|
|
12
13
|
def start
|
13
14
|
log_grpc! if Anycable.config.log_grpc
|
14
|
-
@grpc_server ||= build_server
|
15
15
|
|
16
|
-
|
17
|
-
|
16
|
+
start_http_health_server
|
17
|
+
start_grpc_server
|
18
18
|
end
|
19
19
|
|
20
20
|
def stop
|
@@ -33,12 +33,27 @@ module Anycable
|
|
33
33
|
|
34
34
|
private
|
35
35
|
|
36
|
+
def start_grpc_server
|
37
|
+
@grpc_server ||= build_server
|
38
|
+
|
39
|
+
Anycable.logger.info "RPC server is listening on #{Anycable.config.rpc_host}"
|
40
|
+
Anycable.logger.info "Broadcasting Redis channel: #{Anycable.config.redis_channel}"
|
41
|
+
|
42
|
+
grpc_server.run_till_terminated
|
43
|
+
end
|
44
|
+
|
36
45
|
def build_server
|
37
46
|
GRPC::RpcServer.new.tap do |server|
|
38
47
|
server.add_http2_port(Anycable.config.rpc_host, :this_port_is_insecure)
|
39
48
|
server.handle(Anycable::RPCHandler)
|
40
49
|
end
|
41
50
|
end
|
51
|
+
|
52
|
+
def start_http_health_server
|
53
|
+
return unless Anycable.config.http_health_port_provided?
|
54
|
+
Anycable::HealthServer.start(Anycable.config.http_health_port)
|
55
|
+
at_exit { Anycable::HealthServer.stop }
|
56
|
+
end
|
42
57
|
end
|
43
58
|
end
|
44
59
|
end
|
data/lib/anycable/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: anycable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- palkan
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-09-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: anyway_config
|
@@ -118,16 +118,16 @@ dependencies:
|
|
118
118
|
name: rubocop
|
119
119
|
requirement: !ruby/object:Gem::Requirement
|
120
120
|
requirements:
|
121
|
-
- - "
|
121
|
+
- - "~>"
|
122
122
|
- !ruby/object:Gem::Version
|
123
|
-
version:
|
123
|
+
version: 0.58.0
|
124
124
|
type: :development
|
125
125
|
prerelease: false
|
126
126
|
version_requirements: !ruby/object:Gem::Requirement
|
127
127
|
requirements:
|
128
|
-
- - "
|
128
|
+
- - "~>"
|
129
129
|
- !ruby/object:Gem::Version
|
130
|
-
version:
|
130
|
+
version: 0.58.0
|
131
131
|
- !ruby/object:Gem::Dependency
|
132
132
|
name: simplecov
|
133
133
|
requirement: !ruby/object:Gem::Requirement
|
@@ -187,6 +187,8 @@ files:
|
|
187
187
|
- assets/evlms.png
|
188
188
|
- benchmarks/.gitignore
|
189
189
|
- benchmarks/2017-02-12.md
|
190
|
+
- benchmarks/2018-03-04.md
|
191
|
+
- benchmarks/2018-05-27-rpc-bench.md
|
190
192
|
- benchmarks/HowTo.md
|
191
193
|
- benchmarks/ansible.cfg
|
192
194
|
- benchmarks/benchmark.yml
|
@@ -195,9 +197,11 @@ files:
|
|
195
197
|
- bin/console
|
196
198
|
- bin/setup
|
197
199
|
- circle.yml
|
200
|
+
- etc/bug_report_template.rb
|
198
201
|
- lib/anycable.rb
|
199
202
|
- lib/anycable/config.rb
|
200
203
|
- lib/anycable/handler/exceptions_handling.rb
|
204
|
+
- lib/anycable/health_server.rb
|
201
205
|
- lib/anycable/pubsub.rb
|
202
206
|
- lib/anycable/rpc/rpc_pb.rb
|
203
207
|
- lib/anycable/rpc/rpc_services_pb.rb
|
@@ -226,7 +230,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
226
230
|
version: '0'
|
227
231
|
requirements: []
|
228
232
|
rubyforge_project:
|
229
|
-
rubygems_version: 2.6
|
233
|
+
rubygems_version: 2.7.6
|
230
234
|
signing_key:
|
231
235
|
specification_version: 4
|
232
236
|
summary: Polyglot replacement for ActionCable server
|