guard / guard-spork

Guard::Spork automatically manage Spork DRb servers
https://rubygems.org/gems/guard-spork
MIT License
296 stars 58 forks source link

Two instances of guard-spork for the same test framework run on the same port #78

Closed mcmire closed 12 years ago

mcmire commented 12 years ago

It appears that since guard-spork is telling Spork to use a specific port for a test framework, if there is more than once instance of guard-spork running (say, for two separate apps) then they will clash with each other since they use the same port.

I don't know what the right move is here, but I do know that Spork will find a different port if the default one is already being taken. Something similar to that should probably be done here.

thibaudgg commented 12 years ago

We could update these lines (pull request is welcome) or you can just set a different port manually for each project you're launching no?

mcmire commented 12 years ago

Yeah that is what I am doing now, just setting it manually. And, I mean, it works fine. I think it's something that I would prefer to be figured out for me, though. Here's the rub... even if you automate which port Spork runs under, you have to ensure that when rspec is run, the same --drb-port is used. In theory this is possible, although what if you have multiple Spork guards defined in your Guardfile? Essentially what is needed here is the ability to link a Spork guard to an RSpec guard. Does the #guard method in the API return the Guard object? Then you could store the Spork guard as a variable and then hand it off to the RSpec guard you want to link it to as an option. Good idea, bad idea?

On May 19, 2012, at 1:35 PM, Thibaud Guillaume-Gentilreply@reply.github.com wrote:

We could update these lines (pull request is welcome) or you can just set a different port manually for each project you're launching no?


Reply to this email directly or view it on GitHub: https://github.com/guard/guard-spork/issues/78#issuecomment-5804227

thibaudgg commented 12 years ago

Mmm, the problem is that I'm not even sure that guard-spork could be aware of the port automatically set by Spork, but yes #guard method return guard instance so if possible guard-spork could have a #port method that could be passed to the --drb-port guard-rspec options. That could be a good feature, can you have a look a submit a pull request? Thanks!

mcmire commented 12 years ago

Sweet, yup, you understand what I am going after. I will work on that.

thibaudgg commented 12 years ago

Great!

mcmire commented 12 years ago

After playing around with how it works currently, I feel like fixing Guard won't be a total solution to this problem. The thing is, Guard isn't the only way to run your RSpec tests -- if you need to target a specific test, you drop down to using plain rspec. And if you are running Spork on a different port, you obviously have to tell rspec this port -- manually, through .rspec, via a script, whatever. Which means that getting guard-spork to find an available port and then feed this to guard-rspec will work for Guard, but is useless for running rspec manually -- you end up having to hardcode the Spork port anyway.

So perhaps this issue cannot be fixed in Guard. That said, I feel like there is some way, some place we can make this better. Hardcoding the port is a bit painful because you have to put it in two places -- one in your Guardfile, another in .rspec or wherever. Maybe Spork needs to have a .sporkrc or something where this information can be kept, or the port that Spork runs on can have some sort of string identifier in addition to port number, that way RSpec would know how to connect to it, and RSpec could know about this id through .rspec. Do you have any other thoughts?

thibaudgg commented 12 years ago

Yeah, having the port set in both .rspec & .sporkrc seems like a better approach to me.

Thanks!

jmuheim commented 11 years ago

Hey guys, I ran into this problem, too, and wonder whether you have found a way around it or could point me into a more concrete direction?

I see that I can tell spork which port to use with -p argument, but how can I tell Guard/RSpec/Cucumber to use this?

mcmire commented 11 years ago

You can tell rspec about the port with the --drb-port option. I think Cucumber has a similar option.

Here is the solution I am using at the moment: https://gist.github.com/3814710

jmuheim commented 11 years ago

Thanks a lot, this looks very promising, I will give it a try tomorrow. Have a good night! :-)

jmuheim commented 11 years ago

Okay, this is running quite nice so far. Some questions first:

Now some experiences:

In general, everything works as expected, I tried up to 3 spork&guard combos running in parallel, all fine. BUT: it seems that in some way they interfere, because after some time, when saving a spec file, guard runs the tests without the args, which also means that the --drb-port won't be submitted, so from then on the tests won't run on spork anymore (i guess) but on its own rails instance (the tests also run less fast then). Look at the following output: after the 2nd run of the specs, the arguments are omitted.

$ guard
Guard uses Growl to send notifications.
Guard is now watching at '/Users/josh/Documents/Work/Sientia/iq/gems/iq_bootstrap'
Starting Spork for RSpec
Using RSpec
Loading Spork.prefork block...
Spork is ready and listening on 8902!
Spork server for RSpec successfully started
Guard::RSpec is running, with RSpec 2!
Running all specs
Running tests with args ["--colour", "--format", "progress", "--drb-port", "8902", "-r", "/Users/josh/.rvm/gems/ruby-1.9.3-p0/gems/guard-rspec-1.2.1/lib/guard/rspec/formatters/notification_rspec.rb", "-f", "Guard::RSpec::Formatter::NotificationRSpec", "--out", "/dev/null", "--failure-exit-code", "2", "spec"]...
Run options: include {:focus=>true}

All examples were filtered out; ignoring {:focus=>true}
...............................

Finished in 0.31902 seconds
31 examples, 0 failures
Done.

Running: spec/helpers/iq_bootstrap_helper_spec.rb
Running tests with args ["--colour", "--format", "progress", "--drb-port", "8902", "-r", "/Users/josh/.rvm/gems/ruby-1.9.3-p0/gems/guard-rspec-1.2.1/lib/guard/rspec/formatters/notification_rspec.rb", "-f", "Guard::RSpec::Formatter::NotificationRSpec", "--out", "/dev/null", "--failure-exit-code", "2", "spec/helpers/iq_bootstrap_helper_spec.rb"]...
Run options: include {:focus=>true}

All examples were filtered out; ignoring {:focus=>true}
..............................

Finished in 0.19851 seconds
30 examples, 0 failures
Done.

Running: spec/helpers/iq_bootstrap_helper_spec.rb
Run options: include {:focus=>true}

All examples were filtered out; ignoring {:focus=>true}
..............................

Finished in 0.13145 seconds
30 examples, 0 failures

Running: spec/helpers/iq_bootstrap_helper_spec.rb
Run options: include {:focus=>true}

All examples were filtered out; ignoring {:focus=>true}
..............................

Finished in 0.1313 seconds
30 examples, 0 failures

Running: spec/helpers/iq_bootstrap_helper_spec.rb
Run options: include {:focus=>true}

All examples were filtered out; ignoring {:focus=>true}
..............................

Finished in 0.13427 seconds
30 examples, 0 failures

One other thing is: when I start two guards short after another, then the first process seems to hang itself, while the other one loads properly!

First started guard:

Guard uses Growl to send notifications.
Guard is now watching at '/Users/josh/Documents/Work/Sientia/iq/gems/iq_bla'
Starting Spork for RSpec
Using RSpec
Loading Spork.prefork block...
ERROR: Could not start Spork server for RSpec after 30 seconds. I will continue waiting for a further 60 seconds.

Then when hitting Ctrl-c after a while, it seems to work!

ERROR: Guard::Spork failed to achieve its <start>, exception was:
Interrupt: 
/Users/josh/.rvm/gems/ruby-1.9.3-p0/gems/guard-spork-1.2.0/lib/guard/spork/runner.rb:113:in `sleep'
/Users/josh/.rvm/gems/ruby-1.9.3-p0/gems/guard-spork-1.2.0/lib/guard/spork/runner.rb:113:in `block in wait_for_launch'
/Users/josh/.rvm/gems/ruby-1.9.3-p0/gems/guard-spork-1.2.0/lib/guard/spork/runner.rb:125:in `block in wait_or_loop'
/Users/josh/.rvm/gems/ruby-1.9.3-p0/gems/guard-spork-1.2.0/lib/guard/spork/runner.rb:125:in `times'
/Users/josh/.rvm/gems/ruby-1.9.3-p0/gems/guard-spork-1.2.0/lib/guard/spork/runner.rb:125:in `wait_or_loop'
/Users/josh/.rvm/gems/ruby-1.9.3-p0/gems/guard-spork-1.2.0/lib/guard/spork/runner.rb:112:in `wait_for_launch'
/Users/josh/.rvm/gems/ruby-1.9.3-p0/gems/guard-spork-1.2.0/lib/guard/spork/runner.rb:97:in `verify_launches'
/Users/josh/.rvm/gems/ruby-1.9.3-p0/gems/guard-spork-1.2.0/lib/guard/spork/runner.rb:34:in `launch_sporks'
/Users/josh/.rvm/gems/ruby-1.9.3-p0/gems/guard-spork-1.2.0/lib/guard/spork.rb:21:in `start'
/Users/josh/.rvm/gems/ruby-1.9.3-p0/gems/guard-1.4.0/lib/guard/runner.rb:95:in `block in run_supervised_task'
/Users/josh/.rvm/gems/ruby-1.9.3-p0/gems/guard-1.4.0/lib/guard/runner.rb:93:in `catch'
/Users/josh/.rvm/gems/ruby-1.9.3-p0/gems/guard-1.4.0/lib/guard/runner.rb:93:in `run_supervised_task'
/Users/josh/.rvm/gems/ruby-1.9.3-p0/gems/guard-1.4.0/lib/guard/runner.rb:51:in `block in run'
/Users/josh/.rvm/gems/ruby-1.9.3-p0/gems/guard-1.4.0/lib/guard/runner.rb:166:in `block (3 levels) in scoped_guards'
/Users/josh/.rvm/gems/ruby-1.9.3-p0/gems/guard-1.4.0/lib/guard/runner.rb:165:in `each'
/Users/josh/.rvm/gems/ruby-1.9.3-p0/gems/guard-1.4.0/lib/guard/runner.rb:165:in `block (2 levels) in scoped_guards'
/Users/josh/.rvm/gems/ruby-1.9.3-p0/gems/guard-1.4.0/lib/guard/runner.rb:164:in `catch'
/Users/josh/.rvm/gems/ruby-1.9.3-p0/gems/guard-1.4.0/lib/guard/runner.rb:164:in `block in scoped_guards'
/Users/josh/.rvm/gems/ruby-1.9.3-p0/gems/guard-1.4.0/lib/guard/runner.rb:163:in `each'
/Users/josh/.rvm/gems/ruby-1.9.3-p0/gems/guard-1.4.0/lib/guard/runner.rb:163:in `scoped_guards'
/Users/josh/.rvm/gems/ruby-1.9.3-p0/gems/guard-1.4.0/lib/guard/runner.rb:50:in `run'
/Users/josh/.rvm/gems/ruby-1.9.3-p0/gems/guard-1.4.0/lib/guard.rb:159:in `block in start'
/Users/josh/.rvm/gems/ruby-1.9.3-p0/gems/guard-1.4.0/lib/guard.rb:324:in `block in within_preserved_state'
<internal:prelude>:10:in `synchronize'
/Users/josh/.rvm/gems/ruby-1.9.3-p0/gems/guard-1.4.0/lib/guard.rb:321:in `within_preserved_state'
/Users/josh/.rvm/gems/ruby-1.9.3-p0/gems/guard-1.4.0/lib/guard.rb:158:in `start'
/Users/josh/.rvm/gems/ruby-1.9.3-p0/gems/guard-1.4.0/lib/guard/cli.rb:104:in `start'
/Users/josh/.rvm/gems/ruby-1.9.3-p0/gems/thor-0.16.0/lib/thor/task.rb:27:in `run'
/Users/josh/.rvm/gems/ruby-1.9.3-p0/gems/thor-0.16.0/lib/thor/invocation.rb:120:in `invoke_task'
/Users/josh/.rvm/gems/ruby-1.9.3-p0/gems/thor-0.16.0/lib/thor.rb:275:in `dispatch'
/Users/josh/.rvm/gems/ruby-1.9.3-p0/gems/thor-0.16.0/lib/thor/base.rb:425:in `start'
/Users/josh/.rvm/gems/ruby-1.9.3-p0/gems/guard-1.4.0/bin/guard:6:in `<top (required)>'
/Users/josh/.rvm/gems/ruby-1.9.3-p0/bin/guard:19:in `load'
/Users/josh/.rvm/gems/ruby-1.9.3-p0/bin/guard:19:in `<main>'
/Users/josh/.rvm/gems/ruby-1.9.3-p0/bin/ruby_noexec_wrapper:14:in `eval'
/Users/josh/.rvm/gems/ruby-1.9.3-p0/bin/ruby_noexec_wrapper:14:in `<main>'

Guard::Spork has just been fired
Guard::RSpec is running, with RSpec 2!
Running all specs
Run options: include {:focus=>true}

All examples were filtered out; ignoring {:focus=>true}
...............................

Finished in 0.24808 seconds
31 examples, 0 failures

And here's the 2nd guard (which I ran later, but seems to somehow block the 1st one when launching):

Guard uses Growl to send notifications.
Guard is now watching at '/Users/josh/Documents/Work/Sientia/iq/gems/iq_bootstrap'
Starting Spork for RSpec
Using RSpec
Loading Spork.prefork block...
Spork is ready and listening on 8902!
Spork server for RSpec successfully started
Guard::RSpec is running, with RSpec 2!
Running all specs
Running tests with args ["--colour", "--format", "progress", "--drb-port", "8902", "-r", "/Users/josh/.rvm/gems/ruby-1.9.3-p0/gems/guard-rspec-1.2.1/lib/guard/rspec/formatters/notification_rspec.rb", "-f", "Guard::RSpec::Formatter::NotificationRSpec", "--out", "/dev/null", "--failure-exit-code", "2", "spec"]...
Run options: include {:focus=>true}

All examples were filtered out; ignoring {:focus=>true}
...............................

Finished in 0.32478 seconds
31 examples, 0 failures
Done.

Maybe you have some idea what's going on here so we could fix these items? Did you have similar experiences, or does everything work perfectly for you?

But all in all, I'm quite happy already, at least I can run multiple spork&guard combos in parallel! :) Thanks

jmuheim commented 11 years ago

I have looked into the missing args again, and it seems that only the guard that was started as latest sends the args, all others don't. This is a pitty, any way to make this not happen?

jmuheim commented 11 years ago

I guess I'm getting the idea behind your script/drspec and script/spork files now. If I don't want to use Guard, I can simply start script/spork and run my tests using script/drspec. Right? But why did you name it "drspec" and not "rspec"? Any name collisions? And why not "dspork"?

I hope I don't bug you with my questions, it's just that I'm really eager to understand what I'm doing. :)

mcmire commented 11 years ago

What does "Using Spork has to be opt-in in order to properly customize the DRb port" mean?

Usually you'd add --drb to your .rspec so that if you happen to have Spork running then rspec is run through Spork, otherwise it's not. (Well that's the way I've done it in the past, anyway.) In my setup I chose to remove --drb from .rspec because if you happen to have another instance of Spork running for another application and it's running on the default port, you don't want to send stuff to that Spork inadvertently. So, what this means is that plain rspec now will always run outside of Spork. So then:

why did you name it "drspec" and not "rspec"?

It wasn't really for name collisions, but simply to remind myself that it's the --drb version. This way also if you wanted to (for consistency) define script/rspec which was just an alias for rspec you could do that. You are obviously free to do whatever you want here, that's just how I do it. But that's the general idea.

As for the multiple Guard issues you were seeing, I don't have an immediate answer for that. I'm not seeing any issues myself, but I will look into it.

mcmire commented 11 years ago

I have looked into the missing args again, and it seems that only the guard that was started as latest sends the args, all others don't. This is a pitty, any way to make this not happen?

I think I've figured it out. guard-spork may in fact be the culprit here. It appears that a Spork guard will kill all active Sporks before starting the Sporks that it's responsible for starting: https://github.com/guard/guard-spork/blob/master/lib/guard/spork.rb#L20. So, the second guard command you issue will always kill the Spork that the first guard creates. :(

BTW, the reason I didn't mention this before is because, well, I never really tried this out, to be honest. I find myself starting Spork directly these days rather than rely on Guard to start it (it's one extra process, yes, but in the end I have more manual control). So, I hardly use Spork via Guard -- I should've mentioned that before, sorry.

Regardless, my trick above still works -- it just won't work with Guard right now. I would file another issue to the effect of, if you run two Guards in two different projects on two separate ports, it doesn't work because of the behavior I described above.

EDIT: Okay, I misspoke. Looks like there's an :aggressive_kill option that controls this behavior. It's true by default (https://github.com/guard/guard-spork/blob/master/lib/guard/spork/runner.rb#L20). Why this is I really don't know, but you can set it to false when setting up the spork guard. You'll of course need to do this for every project you want to run simultaneously. I just tested this and it looks like it works.

thibaudgg commented 11 years ago

@mcmire do you know you can skip the kill on start by using the :aggressive_kill => false option?

mcmire commented 11 years ago

@thibaudgg Yup, I just found it, thanks ;)

jmuheim commented 11 years ago

Thank's that has done the trick. :)

Anyway, what's the theory behind aggressive_kill and why is it on false by default?

thibaudgg commented 11 years ago

@sientia-jmu previous version of guard-spork was known to let Spork'ss zombie instances on quit, so it was just a security feature to be sure to have a fresh start on new launch.