Benchmark publication performance

Benchmark publication performance
From 79cba6d0f97fd85050aa7ac6eb27da10e95e2681 Mon Sep 17 00:00:00 2001
From: Ben Langfeld <blangfeld@powerhrg.com>
Date: Wed, 5 Dec 2018 12:08:56 -0200
Subject: [PATCH] Benchmark publication performance


diff --git a/Rakefile b/Rakefile
index c1b61e8..30a3747 100644
--- a/Rakefile
+++ b/Rakefile
@@ -55,5 +55,15 @@ end
 desc "Run tests on all backends, plus client JS tests"
 task spec: backends.map { |backend| "spec:#{backend}" } + [:spec_client_js]
 
-desc "Run all tests, link checks and confirm documentation compiles without error"
+desc "Run performance benchmarks on all backends"
+task :performance do
+  begin
+    ENV['MESSAGE_BUS_BACKENDS'] = backends.join(",")
+    sh "#{FileUtils::RUBY} -e \"ARGV.each{|f| load f}\" #{Dir['spec/performance/*.rb'].to_a.join(' ')}"
+  ensure
+    ENV.delete('MESSAGE_BUS_BACKENDS')
+  end
+end
+
+desc "Run all tests, link checks and confirms documentation compiles without error"
 task default: [:spec, :rubocop, :test_doc]
diff --git a/spec/helpers.rb b/spec/helpers.rb
new file mode 100644
index 0000000..c948aaa
--- /dev/null
+++ b/spec/helpers.rb
@@ -0,0 +1,19 @@
+def wait_for(timeout_milliseconds = 2000)
+  timeout = (timeout_milliseconds + 0.0) / 1000
+  finish = Time.now + timeout
+
+  Thread.new do
+    sleep(0.001) while Time.now < finish && !yield
+  end.join
+end
+
+def test_config_for_backend(backend)
+  config = { backend: backend }
+  case backend
+  when :redis
+    config[:url] = ENV['REDISURL']
+  when :postgres
+    config[:backend_options] = { host: ENV['PGHOST'], user: ENV['PGUSER'] || ENV['USER'], password: ENV['PGPASSWORD'], dbname: ENV['PGDATABASE'] || 'message_bus_test' }
+  end
+  config
+end
diff --git a/spec/performance/publish.rb b/spec/performance/publish.rb
new file mode 100755
index 0000000..b351131
--- /dev/null
+++ b/spec/performance/publish.rb
@@ -0,0 +1,43 @@
+$LOAD_PATH << File.join(File.dirname(__FILE__), '..', '..', 'lib')
+require 'logger'
+require 'benchmark'
+require 'message_bus'
+
+require_relative "../helpers"
+
+backends = ENV['MESSAGE_BUS_BACKENDS'].split(",").map(&:to_sym)
+channel = "/foo"
+iterations = 10_000
+results = []
+
+puts "Running publication benchmark with #{iterations} iterations on backends: #{backends.inspect}"
+
+puts
+Benchmark.bm(10) do |bm|
+  backends.each do |backend|
+    messages_received = 0
+
+    bus = MessageBus::Instance.new
+    bus.configure(test_config_for_backend(backend))
+
+    bus.after_fork
+    bus.subscribe(channel) do |_message|
+      messages_received += 1
+    end
+
+    bm.report(backend) do
+      iterations.times { bus.publish(channel, "Hello world") }
+      wait_for(2000) { messages_received == iterations }
+    end
+
+    results << "[#{backend}]: #{iterations} messages sent, #{messages_received} received, rate of #{(messages_received.to_f / iterations.to_f) * 100}%"
+
+    bus.reset!
+    bus.destroy
+  end
+end
+puts
+
+results.each do |result|
+  puts result
+end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index bf65d31..bdec539 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -7,29 +7,14 @@ require 'message_bus'
 require 'minitest/autorun'
 require 'minitest/spec'
 
+require_relative "helpers"
+
 backend = (ENV['MESSAGE_BUS_BACKEND'] || :redis).to_sym
-MESSAGE_BUS_CONFIG = { backend: backend }
+MESSAGE_BUS_CONFIG = test_config_for_backend(backend)
 require "message_bus/backends/#{backend}"
 PUB_SUB_CLASS = MessageBus::BACKENDS.fetch(backend)
-case backend
-when :redis
-  MESSAGE_BUS_CONFIG.merge!(url: ENV['REDISURL'])
-when :postgres
-  MESSAGE_BUS_CONFIG.merge!(backend_options: { host: ENV['PGHOST'], user: ENV['PGUSER'] || ENV['USER'], password: ENV['PGPASSWORD'], dbname: ENV['PGDATABASE'] || 'message_bus_test' })
-end
 puts "Running with backend: #{backend}"
 
-def wait_for(timeout_milliseconds = 2000)
-  timeout = (timeout_milliseconds + 0.0) / 1000
-  finish = Time.now + timeout
-
-  Thread.new do
-    while Time.now < finish && !yield
-      sleep(0.001)
-    end
-  end.join
-end
-
 def test_only(*backends)
   backend = MESSAGE_BUS_CONFIG[:backend]
   skip "Test doesn't apply to #{backend}" unless backends.include?(backend)

GitHub