async-nats 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/BENCHMARK_RESULTS.md +155 -0
- data/BENCHMARK_SUMMARY.md +94 -0
- data/CHANGELOG.md +37 -0
- data/LICENSE.txt +203 -0
- data/README.md +348 -0
- data/Rakefile +8 -0
- data/benchmark/pub_perf.rb +85 -0
- data/benchmark/pub_sub_perf.rb +117 -0
- data/benchmark/pub_sub_simple.rb +74 -0
- data/benchmark/sub_perf.rb +66 -0
- data/examples/basic-tls.rb +76 -0
- data/examples/basic-usage.rb +66 -0
- data/examples/basic.rb +46 -0
- data/examples/clustered.rb +79 -0
- data/examples/service_api/basic.rb +32 -0
- data/examples/service_api/discovery.rb +31 -0
- data/examples/service_api/errors.rb +33 -0
- data/examples/service_api/groups.rb +30 -0
- data/examples/service_api/stats.rb +40 -0
- data/lib/async/nats/client.rb +332 -0
- data/lib/async/nats/executor.rb +98 -0
- data/lib/async/nats/socket.rb +152 -0
- data/lib/async/nats/version.rb +7 -0
- data/lib/async/nats.rb +12 -0
- data/sig/async/nats.rbs +6 -0
- metadata +206 -0
@@ -0,0 +1,76 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2016-2018 The NATS Authors
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
#
|
16
|
+
|
17
|
+
require "nats/io/client"
|
18
|
+
require "openssl"
|
19
|
+
|
20
|
+
nats = NATS::IO::Client.new
|
21
|
+
|
22
|
+
nats.on_error do |e|
|
23
|
+
puts "Error: #{e}"
|
24
|
+
puts e.backtrace
|
25
|
+
end
|
26
|
+
|
27
|
+
tls_context = OpenSSL::SSL::SSLContext.new
|
28
|
+
tls_context.ssl_version = :TLSv1_2
|
29
|
+
|
30
|
+
# Deactivating this makes it possible to connect to server
|
31
|
+
# skipping hostname validation...
|
32
|
+
tls_context.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
33
|
+
tls_context.verify_hostname = true
|
34
|
+
|
35
|
+
# Set the RootCAs
|
36
|
+
tls_context.cert_store = OpenSSL::X509::Store.new
|
37
|
+
ca_file = File.read("./spec/configs/certs/nats-service.localhost/ca.pem")
|
38
|
+
tls_context.cert_store.add_cert(OpenSSL::X509::Certificate.new(ca_file))
|
39
|
+
|
40
|
+
# The server is setup to use a wildcard certificate for:
|
41
|
+
#
|
42
|
+
# *.clients.nats-service.localhost
|
43
|
+
#
|
44
|
+
# so given the options above, having a wrong domain would
|
45
|
+
# make the client connection fail with an error
|
46
|
+
#
|
47
|
+
# Error: SSL_connect returned=1 errno=0 state=error: certificate verify failed (error number 1)
|
48
|
+
#
|
49
|
+
server = "nats://server-A.clients.nats-service.localhost:4222"
|
50
|
+
|
51
|
+
nats.connect(servers: [server], tls: {context: tls_context})
|
52
|
+
puts "Connected to #{nats.connected_server}"
|
53
|
+
|
54
|
+
nats.subscribe(">") do |msg, reply, subject|
|
55
|
+
puts "Received on '#{subject} #{reply}': #{msg}"
|
56
|
+
nats.publish(reply, "A" * 100) if reply
|
57
|
+
end
|
58
|
+
|
59
|
+
total = 0
|
60
|
+
payload = "c"
|
61
|
+
loop do
|
62
|
+
nats.publish("hello.#{total}", payload)
|
63
|
+
|
64
|
+
begin
|
65
|
+
nats.flush(1)
|
66
|
+
|
67
|
+
# Request which waits until given a response or a timeout
|
68
|
+
msg = nats.request("hello", "world")
|
69
|
+
puts "Received on '#{msg.subject} #{msg.reply}': #{msg.data}"
|
70
|
+
|
71
|
+
total += 1
|
72
|
+
sleep 1
|
73
|
+
rescue NATS::IO::Timeout
|
74
|
+
puts "ERROR: flush timeout"
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2016-2018 The NATS Authors
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
#
|
16
|
+
|
17
|
+
require "nats/io/client"
|
18
|
+
|
19
|
+
nats = NATS::IO::Client.new
|
20
|
+
|
21
|
+
nats.connect(servers: ["nats://127.0.0.1:4222"])
|
22
|
+
puts "Connected to #{nats.connected_server}"
|
23
|
+
|
24
|
+
# Simple subscriber
|
25
|
+
nats.subscribe("foo.>") { |msg, reply, subject| puts "[Received] on '#{subject}': '#{msg}'" }
|
26
|
+
|
27
|
+
# Simple Publisher
|
28
|
+
nats.publish("foo.bar.baz", "Hello World!")
|
29
|
+
|
30
|
+
# Unsubscribing
|
31
|
+
sub = nats.subscribe("bar") { |msg| puts "Received : '#{msg}'" }
|
32
|
+
sub.unsubscribe(2)
|
33
|
+
|
34
|
+
# Subscribers which reply to requests
|
35
|
+
nats.subscribe("help") do |msg, reply, subject|
|
36
|
+
puts "[Received] on '#{subject}' #{reply}: '#{msg}'"
|
37
|
+
nats.publish(reply, "I'll help!") if reply
|
38
|
+
end
|
39
|
+
|
40
|
+
nats.subscribe(">") do |msg, reply, subject|
|
41
|
+
puts "[Received] via wildcard on '#{subject}' #{reply}: '#{msg}'"
|
42
|
+
nats.publish(reply, "Hi") if reply
|
43
|
+
end
|
44
|
+
|
45
|
+
# Requests happens asynchronously if given a callback
|
46
|
+
nats.request("help", "world", max: 2) do |response|
|
47
|
+
puts "[Response] to '#{response.subject}': #{response.data}'"
|
48
|
+
end
|
49
|
+
|
50
|
+
# Request without a callback waits for the response or times out.
|
51
|
+
begin
|
52
|
+
msg = nats.request("help", "please", timeout: 1.0)
|
53
|
+
puts "[Response] '#{msg.subject}': #{msg.data}"
|
54
|
+
rescue NATS::IO::Timeout
|
55
|
+
puts "nats: request timed out"
|
56
|
+
end
|
57
|
+
|
58
|
+
# Server roundtrip which fails if it does not happen within 500ms
|
59
|
+
begin
|
60
|
+
nats.flush(0.5)
|
61
|
+
rescue NATS::IO::Timeout
|
62
|
+
puts "nats: flush timeout"
|
63
|
+
end
|
64
|
+
|
65
|
+
# Closes connection to NATS
|
66
|
+
nats.close
|
data/examples/basic.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2016-2018 The NATS Authors
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
#
|
16
|
+
|
17
|
+
require "nats/io/client"
|
18
|
+
|
19
|
+
nats = NATS::IO::Client.new
|
20
|
+
|
21
|
+
nats.connect(servers: ["nats://127.0.0.1:4222"])
|
22
|
+
puts "Connected to #{nats.connected_server}"
|
23
|
+
|
24
|
+
nats.subscribe(">") do |msg, reply, subject|
|
25
|
+
puts "Received on '#{subject} #{reply}': #{msg}"
|
26
|
+
nats.publish(reply, "A" * 100) if reply
|
27
|
+
end
|
28
|
+
|
29
|
+
total = 0
|
30
|
+
payload = "b"
|
31
|
+
loop do
|
32
|
+
nats.publish("hello.#{total}", payload)
|
33
|
+
|
34
|
+
begin
|
35
|
+
nats.flush(1)
|
36
|
+
|
37
|
+
# Request which waits until given a response or a timeout
|
38
|
+
msg = nats.request("hello", "world")
|
39
|
+
puts "Received on '#{msg.subject} #{msg.reply}': #{msg.data}"
|
40
|
+
|
41
|
+
total += 1
|
42
|
+
sleep 0.0001 if total % 1000 == 0
|
43
|
+
rescue NATS::IO::Timeout
|
44
|
+
puts "ERROR: flush timeout"
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2016-2018 The NATS Authors
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
#
|
16
|
+
|
17
|
+
require "nats/io/client"
|
18
|
+
|
19
|
+
$stdout.sync = true
|
20
|
+
nats = NATS::IO::Client.new
|
21
|
+
|
22
|
+
nats.on_reconnect do
|
23
|
+
puts "Reconnected to server at #{nats.connected_server}"
|
24
|
+
end
|
25
|
+
|
26
|
+
nats.on_disconnect do
|
27
|
+
puts "Disconnected!"
|
28
|
+
end
|
29
|
+
|
30
|
+
nats.on_close do
|
31
|
+
puts "Connection to NATS closed"
|
32
|
+
end
|
33
|
+
|
34
|
+
nats.on_error do |e|
|
35
|
+
puts "Error: #{e}"
|
36
|
+
puts e.backtrace
|
37
|
+
end
|
38
|
+
|
39
|
+
servers = ["nats://127.0.0.1:4222", "nats://127.0.0.1:4223"]
|
40
|
+
|
41
|
+
cluster_opts = {
|
42
|
+
servers: servers,
|
43
|
+
reconnect_time_wait: 1,
|
44
|
+
max_reconnect_attempts: -1, # Infinite reconnects
|
45
|
+
ping_interval: 10,
|
46
|
+
dont_randomize_servers: true,
|
47
|
+
connect_timeout: 2
|
48
|
+
}
|
49
|
+
|
50
|
+
puts "Attempting to connect to #{servers.first}..."
|
51
|
+
nats.connect(cluster_opts)
|
52
|
+
|
53
|
+
puts "Connected to #{nats.connected_server}"
|
54
|
+
|
55
|
+
msgs_sent = 0
|
56
|
+
msgs_received = 0
|
57
|
+
bytes_sent = 0
|
58
|
+
bytes_received = 0
|
59
|
+
|
60
|
+
nats.subscribe("hello") { |msg|
|
61
|
+
msgs_received += 1
|
62
|
+
bytes_received += msg.data.size
|
63
|
+
}
|
64
|
+
|
65
|
+
Thread.new do
|
66
|
+
loop do
|
67
|
+
puts "#{Time.now} #{Thread.list.count} - [Sent/Received] #{msgs_sent}/#{msgs_received} msgs (#{msgs_sent - msgs_received}) | [Received] #{bytes_sent}/#{bytes_received} B (#{bytes_sent - bytes_received})"
|
68
|
+
sleep 1
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
loop do
|
73
|
+
sleep 0.00001
|
74
|
+
|
75
|
+
payload = "world.#{msgs_sent}"
|
76
|
+
nats.publish("hello", payload)
|
77
|
+
msgs_sent += 1
|
78
|
+
bytes_sent += payload.size
|
79
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "nats"
|
4
|
+
|
5
|
+
client = NATS.connect
|
6
|
+
|
7
|
+
service = client.services.add(
|
8
|
+
name: "calc",
|
9
|
+
version: "1.0.0",
|
10
|
+
description: "description"
|
11
|
+
)
|
12
|
+
|
13
|
+
service.on_stop do
|
14
|
+
puts "Service stopped at #{Time.now}"
|
15
|
+
end
|
16
|
+
|
17
|
+
service.endpoints.add("min") do |message|
|
18
|
+
min = JSON.parse(message.data).min
|
19
|
+
message.respond(min.to_json)
|
20
|
+
end
|
21
|
+
|
22
|
+
service.endpoints.add("max") do |message|
|
23
|
+
max = JSON.parse(message.data).max
|
24
|
+
message.respond(max.to_json)
|
25
|
+
end
|
26
|
+
|
27
|
+
min = client.request("min", [5, 100, -7, 34].to_json)
|
28
|
+
max = client.request("max", [5, 100, -7, 34].to_json)
|
29
|
+
|
30
|
+
puts "min = #{min.data}, max = #{max.data}"
|
31
|
+
|
32
|
+
service.stop
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "nats"
|
4
|
+
|
5
|
+
client = NATS.connect
|
6
|
+
|
7
|
+
service = client.services.add(
|
8
|
+
name: "calc",
|
9
|
+
version: "1.0.0"
|
10
|
+
)
|
11
|
+
|
12
|
+
service.endpoints.add("nothing") do |message|
|
13
|
+
message.respond("nothing")
|
14
|
+
end
|
15
|
+
|
16
|
+
puts <<~PING
|
17
|
+
=== PING ===
|
18
|
+
#{client.request("$SRV.PING.calc").data}
|
19
|
+
PING
|
20
|
+
|
21
|
+
puts <<~INFO
|
22
|
+
=== INFO ===
|
23
|
+
#{client.request("$SRV.INFO.calc").data}
|
24
|
+
INFO
|
25
|
+
|
26
|
+
puts <<~STATS
|
27
|
+
=== STATS ===
|
28
|
+
#{client.request("$SRV.STATS.calc").data}
|
29
|
+
STATS
|
30
|
+
|
31
|
+
service.stop
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "nats"
|
4
|
+
|
5
|
+
client = NATS.connect
|
6
|
+
|
7
|
+
service = client.services.add(
|
8
|
+
name: "calc",
|
9
|
+
version: "1.0.0"
|
10
|
+
)
|
11
|
+
|
12
|
+
service.endpoints.add("raise-error") do |message|
|
13
|
+
raise "raise error"
|
14
|
+
end
|
15
|
+
|
16
|
+
service.endpoints.add("class-error") do |message|
|
17
|
+
message.respond_with_error(StandardError.new("class error"))
|
18
|
+
end
|
19
|
+
|
20
|
+
service.endpoints.add("string-error") do |message|
|
21
|
+
message.respond_with_error("string error")
|
22
|
+
end
|
23
|
+
|
24
|
+
service.endpoints.add("hash-error") do |message|
|
25
|
+
message.respond_with_error(code: 503, description: "hash error")
|
26
|
+
end
|
27
|
+
|
28
|
+
puts client.request("raise-error").header
|
29
|
+
puts client.request("class-error").header
|
30
|
+
puts client.request("string-error").header
|
31
|
+
puts client.request("hash-error").header
|
32
|
+
|
33
|
+
service.stop
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "nats"
|
4
|
+
|
5
|
+
client = NATS.connect
|
6
|
+
|
7
|
+
service = client.services.add(
|
8
|
+
name: "calc",
|
9
|
+
version: "1.0.0"
|
10
|
+
)
|
11
|
+
|
12
|
+
arth = service.groups.add("arth")
|
13
|
+
agg = service.groups.add("agg")
|
14
|
+
|
15
|
+
arth.endpoints.add("sum") do |message|
|
16
|
+
sum = JSON.parse(message.data).sum
|
17
|
+
message.respond(sum.to_json)
|
18
|
+
end
|
19
|
+
|
20
|
+
agg.endpoints.add("avg") do |message|
|
21
|
+
data = JSON.parse(message.data)
|
22
|
+
message.respond((data.sum / data.size.to_f).to_json)
|
23
|
+
end
|
24
|
+
|
25
|
+
sum = client.request("arth.sum", [3, 4, 5, 7].to_json)
|
26
|
+
avg = client.request("agg.avg", [3, 4, 5, 7].to_json)
|
27
|
+
|
28
|
+
puts "sum = #{sum.data}, avg = #{avg.data}"
|
29
|
+
|
30
|
+
service.stop
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "nats"
|
4
|
+
|
5
|
+
client = NATS.connect
|
6
|
+
|
7
|
+
service = client.services.add(
|
8
|
+
name: "calc",
|
9
|
+
version: "1.0.0"
|
10
|
+
)
|
11
|
+
|
12
|
+
service.on_stats do |endpoint|
|
13
|
+
errors = endpoint.stats.num_errors
|
14
|
+
requests = endpoint.stats.num_requests
|
15
|
+
|
16
|
+
{ error_rate: (100.0 * errors / requests).round(2) }
|
17
|
+
end
|
18
|
+
|
19
|
+
service.endpoints.add("divide") do |message|
|
20
|
+
dividend, divisor = JSON.parse(message.data)
|
21
|
+
message.respond((dividend / divisor).to_json)
|
22
|
+
end
|
23
|
+
|
24
|
+
client.request("divide", [5, 2].to_json)
|
25
|
+
client.request("divide", [7, 0].to_json)
|
26
|
+
client.request("divide", [3, 1].to_json)
|
27
|
+
client.request("divide", [4, 2].to_json)
|
28
|
+
client.request("divide", [8, 0].to_json)
|
29
|
+
|
30
|
+
puts <<~INFO
|
31
|
+
=== Info ===
|
32
|
+
#{service.info}
|
33
|
+
INFO
|
34
|
+
|
35
|
+
puts <<~STATS
|
36
|
+
=== Stats ===
|
37
|
+
#{service.stats}
|
38
|
+
STATS
|
39
|
+
|
40
|
+
service.stop
|