anycable 0.6.1 → 0.6.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +49 -2
- data/bin/anycable +1 -1
- data/bin/anycabled +30 -0
- data/lib/anycable/broadcast_adapters/redis.rb +1 -1
- data/lib/anycable/cli.rb +1 -1
- data/lib/anycable/config.rb +4 -2
- data/lib/anycable/exceptions_handling.rb +9 -3
- data/lib/anycable/rpc_handler.rb +27 -4
- data/lib/anycable/server.rb +22 -6
- data/lib/anycable/version.rb +1 -1
- metadata +7 -56
- data/.github/ISSUE_TEMPLATE.md +0 -25
- data/.github/PULL_REQUEST_TEMPLATE.md +0 -31
- data/.gitignore +0 -40
- data/.hound.yml +0 -3
- data/.rubocop.yml +0 -71
- data/.travis.yml +0 -16
- data/Gemfile +0 -8
- data/Makefile +0 -5
- data/PITCHME.md +0 -139
- data/PITCHME.yaml +0 -1
- data/Rakefile +0 -8
- data/anycable.gemspec +0 -35
- data/assets/Memory3.png +0 -0
- data/assets/Memory5.png +0 -0
- data/assets/RTT3.png +0 -0
- data/assets/RTT5.png +0 -0
- data/assets/Scheme1.png +0 -0
- data/assets/Scheme2.png +0 -0
- data/assets/cpu_chart.gif +0 -0
- data/assets/cpu_chart2.gif +0 -0
- data/assets/evlms.png +0 -0
- data/benchmarks/.gitignore +0 -2
- data/benchmarks/2017-02-12.md +0 -308
- data/benchmarks/2018-03-04.md +0 -192
- data/benchmarks/2018-05-27-rpc-bench.md +0 -57
- data/benchmarks/2018-10-27.md +0 -181
- data/benchmarks/HowTo.md +0 -23
- data/benchmarks/ansible.cfg +0 -9
- data/benchmarks/assets/2018-10-27-action-cable-rss.png +0 -0
- data/benchmarks/assets/2018-10-27-action-cable-rtt.png +0 -0
- data/benchmarks/assets/2018-10-27-anycable-rss.png +0 -0
- data/benchmarks/assets/2018-10-27-anycable-rtt.png +0 -0
- data/benchmarks/assets/2018-10-27-async-rss.png +0 -0
- data/benchmarks/assets/2018-10-27-async-rtt.png +0 -0
- data/benchmarks/assets/2018-10-27-falcon-cable-rss.png +0 -0
- data/benchmarks/assets/2018-10-27-falcon-cable-rtt.png +0 -0
- data/benchmarks/assets/2018-10-27-iodine-cable-rss.png +0 -0
- data/benchmarks/assets/2018-10-27-iodine-cable-rtt.png +0 -0
- data/benchmarks/assets/2018-10-27-plezi-rss.png +0 -0
- data/benchmarks/assets/2018-10-27-plezi-rtt.png +0 -0
- data/benchmarks/bench.png +0 -0
- data/benchmarks/benchmark.yml +0 -69
- data/benchmarks/hosts +0 -5
- data/benchmarks/rtt_plot.py +0 -74
- data/benchmarks/rtt_plot_test.py +0 -16
- data/benchmarks/servers.yml +0 -58
- data/circle.yml +0 -8
- data/etc/bug_report_template.rb +0 -76
- data/lib/anycable/handler/capture_exceptions.rb +0 -39
- data/protos/rpc.proto +0 -55
data/benchmarks/ansible.cfg
DELETED
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
data/benchmarks/bench.png
DELETED
Binary file
|
data/benchmarks/benchmark.yml
DELETED
@@ -1,69 +0,0 @@
|
|
1
|
-
---
|
2
|
-
- name: Benchmark Client
|
3
|
-
hosts: benchmark
|
4
|
-
sudo: yes
|
5
|
-
remote_user: ubuntu
|
6
|
-
gather_facts: False
|
7
|
-
vars:
|
8
|
-
server_host: '172.31.21.207'
|
9
|
-
hostname: ws-bench-client
|
10
|
-
local_ips: ['172.31.19.119', '172.31.19.120', '172.31.17.121', '172.31.17.122']
|
11
|
-
# local_ips_str: '-l 172.31.19.119 -l 172.31.19.120 -l 172.31.17.121 -l 172.31.17.122'
|
12
|
-
local_ips_str: ''
|
13
|
-
steps: 10
|
14
|
-
step_size: 1000
|
15
|
-
sample_size: 100
|
16
|
-
concurrency: 8
|
17
|
-
payload_size: 200
|
18
|
-
prepare: False
|
19
|
-
log_file: "./last_bench.log"
|
20
|
-
tasks:
|
21
|
-
- name: Prepare the machine
|
22
|
-
tags: prepare
|
23
|
-
block:
|
24
|
-
- hostname:
|
25
|
-
name: "{{ hostname }}"
|
26
|
-
- lineinfile:
|
27
|
-
path: /etc/hosts
|
28
|
-
line: '127.0.0.1 {{ hostname }}'
|
29
|
-
state: present
|
30
|
-
- shell: ip addr add {{ item }}/20 dev eth0
|
31
|
-
with_items: "{{ local_ips }}"
|
32
|
-
|
33
|
-
- name: Print Action Cable command
|
34
|
-
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"
|
35
|
-
tags: action_cable
|
36
|
-
|
37
|
-
- name: Action Cable benchmark
|
38
|
-
become_user: deplo
|
39
|
-
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
|
40
|
-
register: bench
|
41
|
-
tags: action_cable
|
42
|
-
args:
|
43
|
-
chdir: /webapps/anycable_bench
|
44
|
-
ignore_errors: yes
|
45
|
-
|
46
|
-
- name: Print base command
|
47
|
-
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"
|
48
|
-
tags: base
|
49
|
-
|
50
|
-
- name: Base benchmark
|
51
|
-
become_user: deplo
|
52
|
-
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
|
53
|
-
register: bench
|
54
|
-
tags: base
|
55
|
-
args:
|
56
|
-
chdir: /webapps/anycable_bench
|
57
|
-
ignore_errors: yes
|
58
|
-
|
59
|
-
- name: Benchmark results (stdout)
|
60
|
-
debug: var=bench.stdout_lines
|
61
|
-
tags:
|
62
|
-
- action_cable
|
63
|
-
- base
|
64
|
-
|
65
|
-
- name: Benchmark results (stderr)
|
66
|
-
debug: var=bench.stderr_lines
|
67
|
-
tags:
|
68
|
-
- action_cable
|
69
|
-
- base
|
data/benchmarks/hosts
DELETED
data/benchmarks/rtt_plot.py
DELETED
@@ -1,74 +0,0 @@
|
|
1
|
-
#coding: utf-8
|
2
|
-
|
3
|
-
import sys
|
4
|
-
import os
|
5
|
-
import re
|
6
|
-
import argparse
|
7
|
-
|
8
|
-
def process_file(input_file):
|
9
|
-
log = {}
|
10
|
-
log['clients'] = []
|
11
|
-
log['95per'] = []
|
12
|
-
log['min'] = []
|
13
|
-
log['med'] = []
|
14
|
-
log['max'] = []
|
15
|
-
|
16
|
-
for line in input_file:
|
17
|
-
point = parse_line(line)
|
18
|
-
if point:
|
19
|
-
log['clients'].append(point['clients'])
|
20
|
-
log['95per'].append(point['95per'])
|
21
|
-
log['min'].append(point['min'])
|
22
|
-
log['med'].append(point['med'])
|
23
|
-
log['max'].append(point['max'])
|
24
|
-
return log
|
25
|
-
|
26
|
-
def parse_line(line):
|
27
|
-
# clients: 1000 95per-rtt: 1328ms min-rtt: 2ms median-rtt: 457ms max-rtt: 1577ms
|
28
|
-
matches = re.search('clients:\s+(\d+)\s+95per\-rtt:\s+(\d+)ms\s+min\-rtt:\s+(\d+)ms\s+median\-rtt:\s+(\d+)ms\s+max\-rtt:\s+(\d+)ms', line)
|
29
|
-
if matches:
|
30
|
-
return {
|
31
|
-
'clients': int(matches.group(1)),
|
32
|
-
'95per': int(matches.group(2)),
|
33
|
-
'min': int(matches.group(3)),
|
34
|
-
'med': int(matches.group(4)),
|
35
|
-
'max': int(matches.group(5))
|
36
|
-
}
|
37
|
-
return False
|
38
|
-
|
39
|
-
def generate_plot(log, output):
|
40
|
-
import matplotlib.patches as mpatches
|
41
|
-
import matplotlib.pyplot as plt
|
42
|
-
|
43
|
-
with plt.rc_context({'backend': 'Agg'}):
|
44
|
-
|
45
|
-
fig = plt.figure()
|
46
|
-
ax = fig.add_subplot(1, 1, 1)
|
47
|
-
|
48
|
-
ax.plot(log['clients'], log['95per'], '-', lw=1, color='r', label='95 percentile')
|
49
|
-
ax.plot(log['clients'], log['med'], '-', lw=1, color='green', dashes=[10, 5], label='Median')
|
50
|
-
ax.plot(log['clients'], log['max'], '-', lw=1, color='grey', label='Max')
|
51
|
-
|
52
|
-
ax.set_ylabel('RTT ms', color='r')
|
53
|
-
ax.set_xlabel('clients num')
|
54
|
-
ax.set_ylim(0., max(log['max']) * 1.1)
|
55
|
-
|
56
|
-
handles, labels = ax.get_legend_handles_labels()
|
57
|
-
ax.legend(handles, labels, bbox_to_anchor=(0.4, 1))
|
58
|
-
|
59
|
-
ax.grid()
|
60
|
-
|
61
|
-
fig.savefig(output)
|
62
|
-
|
63
|
-
if __name__ == "__main__":
|
64
|
-
parser = argparse.ArgumentParser(description='Generate RTT chart')
|
65
|
-
parser.add_argument('-i', dest='inputfile', type=argparse.FileType('r'), help='input file containing benchmark results', required=True)
|
66
|
-
parser.add_argument('-o', dest='outputfile', type=argparse.FileType('w'), help='output file to write resulted chart PNG', required=True)
|
67
|
-
|
68
|
-
args = parser.parse_args()
|
69
|
-
|
70
|
-
data = process_file(args.inputfile)
|
71
|
-
|
72
|
-
generate_plot(data, args.outputfile)
|
73
|
-
|
74
|
-
print('Done')
|
data/benchmarks/rtt_plot_test.py
DELETED
@@ -1,16 +0,0 @@
|
|
1
|
-
import unittest
|
2
|
-
import os
|
3
|
-
import rtt_plot
|
4
|
-
|
5
|
-
class TestRttPlot(unittest.TestCase):
|
6
|
-
def test_parse_line(self):
|
7
|
-
self.assertEqual(
|
8
|
-
{ 'clients': 1000, '95per': 1328, 'min': 2, 'med': 457, 'max': 1577 },
|
9
|
-
rtt_plot.parse_line(' "clients: 1000 95per-rtt: 1328ms min-rtt: 2ms median-rtt: 457ms max-rtt: 1577ms"')
|
10
|
-
)
|
11
|
-
self.assertFalse(
|
12
|
-
rtt_plot.parse_line('2018/10/28 02:24:13 Missing received broadcasts: expected 23100000, got 23005351')
|
13
|
-
)
|
14
|
-
|
15
|
-
if __name__ == '__main__':
|
16
|
-
unittest.main()
|
data/benchmarks/servers.yml
DELETED
@@ -1,58 +0,0 @@
|
|
1
|
-
---
|
2
|
-
- name: Benchmark Servers
|
3
|
-
hosts: servers
|
4
|
-
sudo: yes
|
5
|
-
remote_user: ubuntu
|
6
|
-
gather_facts: False
|
7
|
-
vars:
|
8
|
-
web_concurrency: 8
|
9
|
-
tasks:
|
10
|
-
- name: Kill servers
|
11
|
-
shell: pid=$(lsof -i:{{item}} -t); kill -TERM $pid || kill -KILL $pid
|
12
|
-
tags:
|
13
|
-
- action_cable
|
14
|
-
- anycable
|
15
|
-
- plezi
|
16
|
-
- iodine_cable
|
17
|
-
- falcon_cable
|
18
|
-
- falcon_async
|
19
|
-
- kill
|
20
|
-
with_items:
|
21
|
-
- "3334"
|
22
|
-
ignore_errors: true
|
23
|
-
- name: Run Action Cable
|
24
|
-
become_user: deplo
|
25
|
-
tags: action_cable
|
26
|
-
command: bash -lc "WEB_CONCURRENCY={{ web_concurrency }} bundle exec rails s -p 3334 -e production"
|
27
|
-
args:
|
28
|
-
chdir: /webapps/anycable_bench/ruby/action-cable-server
|
29
|
-
- name: Run Anycable Go
|
30
|
-
become_user: deplo
|
31
|
-
tags: anycable
|
32
|
-
shell: bash -lc "ANYCABLE_GO_BIN="anycable-go-0.6.0-alpha" ANYCABLE_PORT="3334" bundle exec bin/anycable"
|
33
|
-
args:
|
34
|
-
chdir: /webapps/anycable_bench/ruby/action-cable-server
|
35
|
-
- name: Run Iodine/Plezi
|
36
|
-
become_user: deplo
|
37
|
-
tags: plezi
|
38
|
-
shell: bash -lc "bundle exec iodine -p 3334 -w {{ web_concurrency }} -t 16"
|
39
|
-
args:
|
40
|
-
chdir: /webapps/anycable_bench/ruby/plezi-iodine
|
41
|
-
- name: Run Iodine/ActionCable
|
42
|
-
become_user: deplo
|
43
|
-
tags: iodine_cable
|
44
|
-
shell: bash -lc "RAILS_ENV=production bundle exec iodine -p 3334 -w {{ web_concurrency }} -t 16"
|
45
|
-
args:
|
46
|
-
chdir: /webapps/anycable_bench/ruby/action-cable-server
|
47
|
-
- name: Run Falcon/ActionCable
|
48
|
-
become_user: deplo
|
49
|
-
tags: falcon_cable
|
50
|
-
shell: bash -lc "RAILS_ENV=production bundle exec falcon serve -b http://0.0.0.0:3334"
|
51
|
-
args:
|
52
|
-
chdir: /webapps/anycable_bench/ruby/action-cable-server
|
53
|
-
- name: Run Falcon/Async
|
54
|
-
become_user: deplo
|
55
|
-
tags: falcon_async
|
56
|
-
shell: bash -lc "bundle exec falcon serve -b http://0.0.0.0:3334"
|
57
|
-
args:
|
58
|
-
chdir: /webapps/anycable_bench/ruby/falcon
|
data/circle.yml
DELETED
data/etc/bug_report_template.rb
DELETED
@@ -1,76 +0,0 @@
|
|
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
|
@@ -1,39 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "anycable/rpc/rpc_pb"
|
4
|
-
|
5
|
-
module AnyCable
|
6
|
-
module Handler # :nodoc:
|
7
|
-
# Handle app-level errors.
|
8
|
-
#
|
9
|
-
# NOTE: this functionality couldn't be implemeted
|
10
|
-
# as middleware, 'cause interceptors do not support
|
11
|
-
# aborting the call and returning a data
|
12
|
-
module CaptureExceptions
|
13
|
-
RESPONSE_CLASS = {
|
14
|
-
command: AnyCable::CommandResponse,
|
15
|
-
connect: AnyCable::ConnectionResponse,
|
16
|
-
disconnect: AnyCable::DisconnectResponse
|
17
|
-
}.freeze
|
18
|
-
|
19
|
-
RESPONSE_CLASS.keys.each do |mid|
|
20
|
-
module_eval <<~CODE, __FILE__, __LINE__ + 1
|
21
|
-
def #{mid}(*)
|
22
|
-
capture_exceptions(:#{mid}) { super }
|
23
|
-
end
|
24
|
-
CODE
|
25
|
-
end
|
26
|
-
|
27
|
-
def capture_exceptions(method_name)
|
28
|
-
yield
|
29
|
-
rescue StandardError => exp
|
30
|
-
AnyCable::ExceptionsHandling.notify(exp)
|
31
|
-
|
32
|
-
RESPONSE_CLASS.fetch(method_name).new(
|
33
|
-
status: AnyCable::Status::ERROR,
|
34
|
-
error_msg: exp.message
|
35
|
-
)
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
data/protos/rpc.proto
DELETED
@@ -1,55 +0,0 @@
|
|
1
|
-
syntax = "proto3";
|
2
|
-
|
3
|
-
package anycable;
|
4
|
-
|
5
|
-
service RPC {
|
6
|
-
rpc Connect (ConnectionRequest) returns (ConnectionResponse) {}
|
7
|
-
rpc Command (CommandMessage) returns (CommandResponse) {}
|
8
|
-
rpc Disconnect (DisconnectRequest) returns (DisconnectResponse) {}
|
9
|
-
}
|
10
|
-
|
11
|
-
enum Status {
|
12
|
-
ERROR = 0;
|
13
|
-
SUCCESS = 1;
|
14
|
-
FAILURE = 2;
|
15
|
-
}
|
16
|
-
|
17
|
-
message ConnectionRequest {
|
18
|
-
string path = 1;
|
19
|
-
map<string,string> headers = 2;
|
20
|
-
}
|
21
|
-
|
22
|
-
message ConnectionResponse {
|
23
|
-
Status status = 1;
|
24
|
-
string identifiers = 2;
|
25
|
-
repeated string transmissions = 3;
|
26
|
-
string error_msg = 4;
|
27
|
-
}
|
28
|
-
|
29
|
-
message CommandMessage {
|
30
|
-
string command = 1;
|
31
|
-
string identifier = 2;
|
32
|
-
string connection_identifiers = 3;
|
33
|
-
string data = 4;
|
34
|
-
}
|
35
|
-
|
36
|
-
message CommandResponse {
|
37
|
-
Status status = 1;
|
38
|
-
bool disconnect = 2;
|
39
|
-
bool stop_streams = 3;
|
40
|
-
repeated string streams = 4;
|
41
|
-
repeated string transmissions = 5;
|
42
|
-
string error_msg = 6;
|
43
|
-
}
|
44
|
-
|
45
|
-
message DisconnectRequest {
|
46
|
-
string identifiers = 1;
|
47
|
-
repeated string subscriptions = 2;
|
48
|
-
string path = 3;
|
49
|
-
map<string,string> headers = 4;
|
50
|
-
}
|
51
|
-
|
52
|
-
message DisconnectResponse {
|
53
|
-
Status status = 1;
|
54
|
-
string error_msg = 2;
|
55
|
-
}
|