Why are my specs while using Guard so slow? - ruby

When I run my specs using just spork, I get quite a significant performance increase
$ time rspec .
.....
Finished in 11.39 seconds
5 examples, 0 failures
real 0m11.780s
user 0m10.318s
sys 0m1.180s
and with spork
$ time rspec . --drb
.....
Finished in 107.24 seconds
5 examples, 0 failures
real 0m1.968s
user 0m0.488s
sys 0m0.095s
which is really awesome. But once I put guard into play, it seems that everything runs so slow, as if there was no spork at all.
$ guard
Guard is now watching at '/Users/darth/projects/scvrush'
Starting Spork for RSpec
Using RSpec
Preloading Rails environment
Loading Spork.prefork block...
Spork is ready and listening on 8989!
Spork server for RSpec successfully started
Guard::RSpec is running, with RSpec 2!
Running all specs
.....
Finished in 10.77 seconds
5 examples, 0 failures
even if I don't look at the Finished in 10.77 seconds, I can count at least 6-8 seconds every time it tries to run a spec, even for just one model.
I did some minor edits to the Guardfile, such as :wait => 120, but that should only affect when guard is starting up.

You have to pass the --drb option for rspec in your Guardfile, like this:
guard 'rspec', :version => 2, :cli => '--drb' do
...
end

Related

What is the correct way to end a WEBrick server process after a timeout?

I'm trying to implement a small WEBrick server that ends itself when there are no requests after x number of seconds. However, I'm getting nowhere. My very first attempt at simply exiting after 2 seconds fails. Here's the simple code
that doesn't work.
server = WEBrick::HTTPServer.new(:Port => 8000)
WEBrick::Utils::TimeoutHandler.register(2, Timeout::Error)
server.start
I thought that would simply exit the process after 2 seconds. Here's what actually happens:
[2020-01-19 15:41:10] INFO WEBrick 1.4.2
[2020-01-19 15:41:10] INFO ruby 2.5.1 (2018-03-29) [x86_64-linux-gnu]
[2020-01-19 15:41:10] INFO WEBrick::HTTPServer#start: pid=16622 port=8000
[2020-01-19 15:41:12] ERROR Timeout::Error: execution timeout
/usr/lib/ruby/2.5.0/webrick/server.rb:170:in `select'
And then the process keeps running. I have to ctrl-c to end it.
What's the correct way to shut down a server and end the process after a timeout?

Performance of classic sinatra and modular sinatra? am I doing wrong?

UPDATED: OK, problem solved.
The different way I started the server makes the different result .
# this gives 2800 req/s in a production server, server based on thin
$ bundle exec thin start -R config.ru -e production
# this gives 1600 req/s in the same server, server based on Rack( seems that)
$ bundle exec rackup config.ru -s thin
so the ways of starting sinatra:
wrong: $ ruby main.rb (based on rack?)
wrong: $ rackup config.ru (based on rack)
wrong: $ rackup config.ru -s thin ( event based on rack)
correct: $ thin start -R config.ru -e production
------------------- Original question --------------------
Today I am coding Sinatra for an API application, and found that:
Classic sinatra code can process :
1.1 1800 request/s, with thin as the server.
1.2 2000 request/s, with puma as the server.
Modular sinatra code can only process:
2.1 1100 requests/s, with thin as the server
2.2 800 requests/s , with puma as the server.
How to reproduce this:
classic sinatra
# test_classic_sinatra.rb
require 'sinatra'
get '/' do
'hihihi'
end
run :
siwei $ ruby test.rb
== Sinatra (v2.0.5) has taken the stage on 4567 for development with backup from Thin
Thin web server (v1.7.2 codename Bachmanity)
Maximum connections set to 1024
Listening on localhost:4567, CTRL+C to stop
test:
$ ab -n 1000 -c 100 http://localhost:4567/
and got result:
Concurrency Level: 100
Time taken for tests: 0.530 seconds
Complete requests: 1000
Failed requests: 0
Total transferred: 211000 bytes
HTML transferred: 6000 bytes
Requests per second: 1885.43 [#/sec] (mean)
Time per request: 53.038 [ms] (mean)
Time per request: 0.530 [ms] (mean, across all concurrent requests)
Transfer rate: 388.50 [Kbytes/sec] received
Modular sinatra:
# config.ru
require 'sinatra/base'
class App < Sinatra::Application
set :environment, :production
get '/' do
'hihihi'
end
end
run App
with thin as server
run:
$ rackup config.ru -s thin
Thin web server (v1.7.2 codename Bachmanity)
Maximum connections set to 1024
Listening on localhost:9292, CTRL+C to stop
test:
Concurrency Level: 100
Time taken for tests: 0.931 seconds
Complete requests: 1000
Failed requests: 0
Total transferred: 211000 bytes
HTML transferred: 6000 bytes
Requests per second: 1073.58 [#/sec] (mean)
Time per request: 93.146 [ms] (mean)
Time per request: 0.931 [ms] (mean, across all concurrent requests)
Transfer rate: 221.22 [Kbytes/sec] received
with puma as server
run:
siwei$ rackup config.ru
Puma starting in single mode...
* Version 3.11.4 (ruby 2.3.8-p459), codename: Love Song
* Min threads: 0, max threads: 16
* Environment: development
* Listening on tcp://localhost:9292
Use Ctrl-C to stop
test:
$ab -n 1000 -c 100 http://localhost:9292/
got result:
Concurrency Level: 100
Time taken for tests: 1.266 seconds
Complete requests: 1000
Failed requests: 0
Total transferred: 178000 bytes
HTML transferred: 6000 bytes
Requests per second: 789.62 [#/sec] (mean)
Time per request: 126.643 [ms] (mean)
Time per request: 1.266 [ms] (mean, across all concurrent requests)
Transfer rate: 137.26 [Kbytes/sec] received
Before deciding to use Sinatra, I read many posts about "sinatra, grape and rails api", and I ran test agaist these frameworks, and finally decide to use Sinatra.
But now , I found Modular Sinatra seems not so good as expected. Could someone give me a clue about how to use "Classic Sinatra" or "Modular Sinatra" ?
If I don't use Modular Sinatra, how to write code for big applications?
thanks a lot!
Your benchmark is incorrect.
According to the snippets you posted, in the first case you use Thin as a server and in the second it's Puma.
These servers implement absolutely different concurrency models: as far as I remember it is a single-threaded event loop for the former and multiple threads for the latter. As a result, Thin performs better for light non-blocking tasks while Puma beats it in the scenarios with relatively heavy computations or blocking ones.
Your dummy example just better fits to the Thin's model and this causes the difference... Modular Sinatra should be absolutely fine, just compare apples to apples :)
OK, I found the root cause, and with The Tin Man's suggestion, I post my answer here.
The problem is the "web server" , but not the "framework"
The different way I started the server makes the different result .
# this gives 2800 req/s in a production server, server based on thin
$ bundle exec thin start -R config.ru -e production
# this gives 1600 req/s in the same server, server based on Rack( seems that)
$ bundle exec rackup config.ru -s thin
so the ways of starting sinatra:
wrong: $ ruby main.rb (based on rack?)
wrong: $ rackup config.ru (based on rack)
wrong: $ rackup config.ru -s thin ( event based on rack)
correct: $ thin start -R config.ru -e production

Thread deadlock on simple operations in pry

[Note: I "fixed" this problem by creating and using a new gemset. I'm still curious why the problem occurred but it is no longer blocking me.]
[I am aware that there is a similar issue at Deadlock in Ruby join(), but I have tried the timeout parameter suggested there and it does not help. I suspect there is a pry-specific problem not covered there.]
I am getting the error below when running the code below, but only when executed within a pry session. This code has not been changed and has been working fine for quite a while, and I have no idea why it's an issue just now. I am using pry version 0.11.3 on Ruby 2.5.1. Also, this code works fine when pasted into pry; it's not working in my wifi-wand application that launches pry in the context of one of its objects (gem install wifi-wand to install, https://github.com/keithrbennett/wifiwand is the project page).
domains = %w(google.com baidu.com)
puts "Calling dig on domains #{domains}..." if #verbose_mode
threads = domains.map do |domain|
Thread.new do
output = `dig +short #{domain}`
output.length > 0
end
end
threads.each(&:join)
[1] pry(#<WifiWand::CommandLineInterface>)> ci
Calling dig on domains ["google.com", "baidu.com"]...
fatal: No live threads left. Deadlock?
3 threads, 3 sleeps current:0x00007fbd13d0c5a0 main thread:0x00007fbd13d0c5a0
* #<Thread:0x00007fbd14069c20 sleep_forever>
rb_thread_t:0x00007fbd13d0c5a0 native:0x00007fff89c2b380 int:0
/Users/kbennett/work/wifi-wand/lib/wifi-wand/models/base_model.rb:89:in `join'
/Users/kbennett/work/wifi-wand/lib/wifi-wand/models/base_model.rb:89:in `each'
/Users/kbennett/work/wifi-wand/lib/wifi-wand/models/base_model.rb:89:in `block in connected_to_internet?'
/Users/kbennett/work/wifi-wand/lib/wifi-wand/models/base_model.rb:126:in `connected_to_internet?'
/Users/kbennett/work/wifi-wand/lib/wifi-wand/command_line_interface.rb:264:in `cmd_ci'
Strangely, the problem was fixed by uninstalling and reinstalling the awesome_print gem. I have no idea why.

Intermittently breaking tests in my hand-rolled Sinatra app. Related to file processing?

Summary: After adding logic to save user account data, my code seems to work fine and sometimes all my (many) tests pass. But sometimes they fail seemingly randomly, with /tmp test files not being deleted during testing.
In my hand-rolled Ruby/Sinatra "to do list" program, I added user accounts and can now save data to user files (.yml format) as well as tmp files for people who aren't logged in. Yay!
As far as I can tell, the code works fine. All tests pass...but only sometimes. Sometimes, the tests related to my new file processing methods fail. Here's a sample:
# Running:
....EF..........................
Finished in 3.930466s, 8.1415 runs/s, 53.1744 assertions/s.
1) Error:
ToDoTest#test_post_newtask:
Errno::EACCES: Permission denied # unlink_internal - tmp/1.yml
C:/Users/user/Dropbox/_Programming/Ruby/learning_projects/todo/test/test_todo.rb:404:in `delete'
C:/Users/user/Dropbox/_Programming/Ruby/learning_projects/todo/test/test_todo.rb:404:in `block (2 levels) in teardown'
C:/Users/user/Dropbox/_Programming/Ruby/learning_projects/todo/test/test_todo.rb:404:in `each'
C:/Users/user/Dropbox/_Programming/Ruby/learning_projects/todo/test/test_todo.rb:404:in `block in teardown'
2) Failure:
ToDoTest#test_get_deleted [C:/Users/user/Dropbox/_Programming/Ruby/learning_projects/todo/test/test_todo.rb:167]:
Expected false to be truthy.
32 runs, 209 assertions, 1 failures, 1 errors, 0 skips
rake aborted!
Command failed with status (1): [ruby -I"lib" -I"C:/Ruby23/lib/ruby/gems/2.3.0/gems/rake-10.4.2/lib" "C:/Ruby23/lib/ruby/gems/2.3.0/gems/rake-10.4.2/lib/rake/rake_test_loader.rb" "test/test_task.rb" "test/test_task_store.rb" "test/test_todo.rb" "test/test_todo_helpers.rb" "test/test_users.rb" ]
Tasks: TOP => default => test
(See full trace by running task with --trace)
This is only a sample, because sometimes many more tests fail or have errors. It's weirdly random. I noticed that my tests, which result in a lot /tmp files being made and deleted very rapidly, sometimes failed to delete some files, and as a result some would be left behind. If I reran my tests when there were some undeleted files in /tmp, there would be even more (again, random) errors.
One common error I saw, which I never saw before adding the new file processing commands, is this one: Errno::EACCES: Permission denied # unlink_internal. I looked this up on SO but there seems to be only (irrelevant-seeming) Rails stuff. This is a Sinatra program running on Windows. So could I replicate the tests in my Ubuntu VM? Yes I could. Precisely the same sort of error pattern.
Anyway, I suspected that system commands were not finishing before execution continued. But apparently not. I tried putting "sleep 2" after all my system commands, and I still got a random failing test and cruft left in /tmp. I also tried using threads, which I have never used before, like this:
delr = Thread.new do
File.delete(#store.path) # seems to help to add this here...
end
delr.join
But that didn't help.
One other thing...I'm teaching myself and this is probably not the way it's supposed to be done, but...all of my get methods are preceded by a check of my session[:id] variable to see if the user is logged in, and to see if the correct datafile is loaded. I don't know if that's relevant but it might be.
Any ideas on what the problem could be or how to fix it?

Rails 3 "rake test" command output

running "rake test" with a simple Rails 3 project gives me the following output.
Why are two suites listed? I have one default test with "assert true" which is counted in the first suite but not the second.
Any ideas? I know Ruby 1.9 replaced Test::Unit with MiniTest which has caused some issues, but after a few hours Googling I haven't found an explanation for this output.
NOTICE: CREATE TABLE (etc.)
Loaded suite /Users/me/.rvm/gems/ruby-1.9.2-head#rails/gems/rake-0.8.7/lib/rake/rake_test_loader
Started
.
Finished in 0.030670 seconds.
1 tests, 1 assertions, 0 failures, 0 errors, 0 skips
Test run options: --seed 14141
Loaded suite /Users/me/.rvm/gems/ruby-1.9.2-head#rails/bin/rake
Started
Finished in 0.003156 seconds.
0 tests, 0 assertions, 0 failures, 0 errors, 0 skips
Test run options: --seed 56342

Resources