0

For those of you who know what you're talking about I apologise for butchering the way that I'm going to phrase this question. I know nothing about bash whatsoever. With that caveat out of the way, let me get out my cleaver...

I am building a Rails app which has what's called a procfile which sets up any processes that need to be run in different environments

e.g.

web: bundle exec unicorn -p $PORT -c ./config/unicorn.rb
redis: redis-server
worker: bundle exec sidekiq
proxylocal: bin/proxylocal_local

Each one of these lines specs a process to be run. It also expects a pid to be returned after the process spins up. The syntax is

process_name: process_invokation_script

However the last process, proxylocal, only actually starts a process in development. In production it doesn't do anything.

Unfortunately that causes the Procfile to choke as it needs a process ID returned. So is there some super-simple, zero-overhead process that I can spawn in that case just to keep the procfile happy?

Peter Nixey
  • 16,187
  • 14
  • 79
  • 133
  • Nothing that you can create has strictly zero overhead. However, on Linux, process creation (via [fork(2)](http://man7.org/linux/man-pages/man2/fork.2.html) and [execve(2)](http://man7.org/linux/man-pages/man2/execve.2.html) ...) is quite cheap. – Basile Starynkevitch Aug 04 '14 at 15:43
  • If you can vary the behavior of `proxylocal` (or is it `proxylocal_local`?) between development and production environments, why can't you vary the contents of the procfile? Or perhaps that would be a bad idea, since the development and production environments should be, at least in some ways, as similar as possible. – Keith Thompson Aug 04 '14 at 17:30
  • How long does this process need to run? If the process ran very quickly and, later on, another process used the same PID, would that be a problem? – Keith Thompson Aug 04 '14 at 20:33
  • I honestly don't know @KeithThompson. I will have a play with the sleep command. I'm not sure whether Foreman will attempt to restart a closed process. Is there any reason why using `cat` would be bad? – Peter Nixey Aug 05 '14 at 10:18
  • @PeterNixey: I don't know what Foreman is; you might read its documentation to get a better idea of what it does with `proxylocal`. I wouldn't use `cat`; it tries to read from its standard input. The intent is for it to hang waiting for input, but depending on how its environment is set up it might terminate immediately (like `cat < /dev/null`). – Keith Thompson Aug 05 '14 at 14:08

3 Answers3

4

The sleep command does nothing for a specified period of time, with very low overhead. Give it an argument longer than your code will run.

For example

sleep 2147483647

does nothing for 231-1 seconds, just over 68 years. I picked that number because any reasonable implementation of sleep should be able to handle it.

In the unlikely event that that doesn't work (say if you're on an old 16-bit system that can't sleep for more than 216-1 seconds), you can do a sleep in an infinite loop:

sh -c 'while : ; do sleep 30000 ; done'

This assumes that you need the process to run for a very long time; that depends on what your application needs to do with the process ID. If it's required to be unique as long as the application is running, you need something that will continue to run for a long time; if the process terminates, its PID can be re-used by another process.

If that's not a requirement, you can use sleep 0 or true, which will terminate immediately.

If you need to give the application a little time to get the process ID before the process terminates, something like sleep 10 or even sleep 1 might work, though determining just how long it needs to run can be tricky and error-prone.

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
  • 1
    +1. Exactly what I was thinking but not sure if it's necessary that `sleep` would run for a long time. If PID is the only thing needed, perhaps only 10 seconds would do. – konsolebox Aug 04 '14 at 16:32
  • @konsolebox: If it doesn't need to run for a long time, does it need to run for any significant time at all? If `sleep 10` would suffice, why not `sleep 0` or `true`? If the purpose is to obtain a guaranteed-unique process ID, it needs to sleep for a long time; otherwise a new process could easily re-use the same PID. – Keith Thompson Aug 04 '14 at 17:28
  • 1
    @KeithThompson the only reason I didn't suggest this is because you can't technically make sleep run forever (well maybe `while true; do sleep 1000; done` or something). Of course, running for 68 years is practically the same thing, but I like solutions to be as robust as possible. – Explosion Pills Aug 04 '14 at 20:32
1

If Heroku isn't doing anything with proxylocal I'm not sure why you'd even want this in your Procifle. I'm also a bit confused about whether you want to change the Procfile or what bin/proxylocal_local does and how you would even do that.

That being said, if you are able to do anything you like for production your script can just call cat and it will create a pid and then just sit waiting for the next command (which never comes).

Peter Nixey
  • 16,187
  • 14
  • 79
  • 133
Explosion Pills
  • 188,624
  • 52
  • 326
  • 405
  • I'm putting it in the procfile so that it's there and defined for the development environment. Unfortunately returning `true` from the script doesn't seem to work - it still returns `16:48:45 proxylocal.1 | exited with code 0` – Peter Nixey Aug 04 '14 at 15:48
  • @PeterNixey I guess the script can't exit either .. try just doing `cat`. It will wait for input forever. Overhead should be minimal, but not nonexistent. – Explosion Pills Aug 04 '14 at 15:50
  • ahh, that's great. Did the job a treat. Thank you. I've accepted your answer but if you could add the `cat` pointer in there then it would be really helpful for anyone else. Thank you – Peter Nixey Aug 04 '14 at 16:02
  • 2
    If you need it not to exit, `sleep 2147483648` should do the trick; it does nothing for about 68 years. The `cat` trick might cause problems because it tries to read from `stdin`. – Keith Thompson Aug 04 '14 at 16:16
  • 2
    I meant `sleep 2147483647` – Keith Thompson Aug 04 '14 at 16:26
  • It's likely that `cat` would be invoked with no standard input and would terminate immediately. Maybe that would work, but if having the process terminate immediately is acceptable you might as well do `true` or `sleep 0`. – Keith Thompson Aug 05 '14 at 14:09
0

For truly minimal overhead, you don't want to run any external commands. When the shell starts a command, it first forks itself, then the child shell execs the external command. If the forked child can run a builtin, you can skip the exec.

Start by creating a read-only fifo somewhere.

mkfifo foo
chmod 400 foo

Then, whenever you need a do-nothing process, just fork a shell which tries to read from the fifo. It's read-only, so no one can write to it, so all reads will block.

read < foo &
chepner
  • 497,756
  • 71
  • 530
  • 681