Is there a way to know when actually a server is stopped at EventMachine? - ruby

Using EM::stop_server schedules the server to be stopped. How can I know when the server is actually stopped?
require 'eventmachine'
class TestServer < EM::Connection
def post_init
send_data "Welcome\r\n"
end
end
class TestClient < EM::Connection
def receive_data(data)
puts data
end
end
Thread.new do
EM.run { }
end
while !EM.reactor_running? ; end
g = EM::start_server('127.0.0.1', 6667, TestServer)
EM::stop_server(g)
#sleep(1)
EM::connect('127.0.0.1', 6667, TestClient)
sleep
Running the above outputs Welcome. However if I uncomment sleep(1), nothing is printed.
Is there a way to achieve something similar without using sleep? Like using EM.reactor_running? to check if EM reactor's has started but to check if a server has been stopped.

Related

How to start Drb service concurrently with other methods in Windows

I want to run the startdrb method concurrently with the printstuff method on a Windows system. I messed around with Thread.new but the service starts and terminates after the thread completes.
How would this be written?
require 'drb'
require 'drb/ssl'
class TestDRB
def dostuff
...
end
def startdrb
begin
config = {SSLCertName: [["CN","DRuby"]]}
DRb.start_service("drbssl://127.0.0.1:9911", BHRBeacon.new, config)
rescue Exception => e
puts e.full_message
end
def printstuff
begin
puts "this will run while Drb service is also running"
end
TestDRB.new.startdrb
TestDRB.new.printstuff

Running Sinatra app inside Thread doesn't work

I'm trying to run a Sinatra app in a new Thread in order to also run some other thing inside my script but when I do:
require 'sinatra/base'
class App < Sinatra::Base
...some routes...
end
Thread.new do
App.run!
end
Nothing happens and Sinatra server is not started. Is there anything I'm missing in order to achieve this?
Finally I run the other ruby process in a Thread but from Sinatra application and it works just fine.
class App < Sinatra::Base
threads = []
threads <<
Thread.new do
Some::Other::Thing
rescue StandardError => e
$stderr << e.message
$stderr << e.backtrace.join("\n")
end
trap('INT') do
puts 'trapping'
threads.each do |t|
puts 'killing'
Thread.kill t
end
end
run!
end
And I added a control when Sinatra app is exited also kill the open thread.

Ruby EventMachine testing

My first question concerning Ruby.
I'm trying to test EventMachine interaction inside the Reactor loop - I guess it could be classified as "functional" testing.
Say I have two classes - a server and a client. And I want to test both sides - I need to be sure about their interaction.
Server:
require 'singleton'
class EchoServer < EM::Connection
include EM::Protocols::LineProtocol
def post_init
puts "-- someone connected to the echo server!"
end
def receive_data data
send_data ">>>you sent: #{data}"
close_connection if data =~ /quit/i
end
def unbind
puts "-- someone disconnected from the echo server!"
end
end
Client:
class EchoClient < EM::Connection
include EM::Protocols::LineProtocol
def post_init
send_data "Hello"
end
def receive_data(data)
#message = data
p data
end
def unbind
puts "-- someone disconnected from the echo server!"
end
end
So, I've tried different approaches and came up with nothing.
The fundamental question is - could I somehow test my code with RSpec, using should_recive?
EventMachine parameter should be a class or a module, so I can't send instantiated/mocked code inside. Right?
Something like this?
describe 'simple rspec test' do
it 'should pass the test' do
EventMachine.run {
EventMachine::start_server "127.0.0.1", 8081, EchoServer
puts 'running echo server on 8081'
EchoServer.should_receive(:receive_data)
EventMachine.connect '127.0.0.1', 8081, EchoClient
EventMachine.add_timer 1 do
puts 'Second passed. Stop loop.'
EventMachine.stop_event_loop
end
}
end
end
And, if not, how would you do it with EM::SpecHelper? I have this code using it, and can't figure out what I'm doing wrong.
describe 'when server is run and client sends data' do
include EM::SpecHelper
default_timeout 2
def start_server
EM.start_server('0.0.0.0', 12345) { |ws|
yield ws if block_given?
}
end
def start_client
client = EM.connect('0.0.0.0', 12345, FakeWebSocketClient)
yield client if block_given?
return client
end
describe "examples from the spec" do
it "should accept a single-frame text message" do
em {
start_server
start_client { |client|
client.onopen {
client.send_data("\x04\x05Hello")
}
}
}
end
end
end
Tried a lot of variations of these tests and I just can't figure it out. I'm sure I'm missing something here...
Thanks for your help.
The simplest solution that I can think of is to change this:
EchoServer.should_receive(:receive_data)
To this:
EchoServer.any_instance.should_receive(:receive_data)
Since EM is expecting a class to start a server, the above any_instance trick will expect any instance of that class to receive that method.
The EMSpecHelper example (while being official/standard) is quite convoluted, I'd rather stick with the first rspec and use any_instance, just for simplicity's sake.

ruby-eventmachine use start_server with an instance

I'm new to ruby and maybe this is a very simple question..
I'd like to use eventmachine to develop a simulator for my tests.
Following example in documentation I can write something like this:
require 'eventmachine'
class Server< EM::Connection
def receive_data data
send_data data
close_connection_after_writing
end
end
#Note that this will block current thread.
EventMachine.run {
EventMachine.start_server '127.0.0.1','8080', Server
}
But I wonder if there is a way to use an instance of class, something like:
require 'eventmachine'
class Server< EM::Connection
attr_accessor :response
def receive_data data
send_data #response
close_connection_after_writing
end
end
server1 = Server.new
server1.response = "foo"
#Note that this will block current thread.
EventMachine.run {
EventMachine.start_server '127.0.0.1','8080', server1
}
I try to read source code..but it's too hard for me.
I'm surely missing something, but I don't know how to do something like this.
As I say there was something that I was missing.
You can add parameters for class to be instantiated :
class Server< EM::Connection
def initialize par
puts "I'm server number#{par}"
end
def receive_data data
send_data data
close_connection_after_writing
end
end
EventMachine.run {
EventMachine.start_server '127.0.0.1','8080', Server,1
}
EventMachine.run {
EventMachine.start_server '127.0.0.1','8080', Server,2
}
So I will customize instance behaviour with parameters

EventMachine is terrifyingly slow

Is there any reason that in my application, the send_data method lags terribly? My telnet (many other clients tested with same result) window wait 1-2 seconds before displying the data sent.
The following application has no lag:
require 'eventmachine'
class AreaServer < EventMachine::Connection
attr_accessor :options, :status
def receive_data(data)
send_data("I got: #{data}\r\n")
end
end
EM.run do
EM.start_server '192.168.0.199', 4000, AreaServer do |conn|
conn.options = {:my => 'options'}
conn.status = :OK
end
end
so I suspect it's not a networking problem.
It seemed the output stream kept open after writing, so I tried to find a solution to close this stream.
If you write close_connection_after_writing to receive_data, the stream will be closed after write. I guess you should turn off the keep_alive option.
class AreaServer < EventMachine::Connection
attr_accessor :options, :status
def receive_data(data)
send_data("I got: #{data}\n")
close_connection_after_writing
end
end

Resources