To `exec` or not to `exec`, what is the standard?


#1

Hello,

This just came up in an Issue 1783. Basically because there was an exec foo that exited that was causing habitat to restart constantly.

From my understanding, the difference is that exec causes the child process to “replace” the current process.

I’m not so sure the implications from a Habitat perspective… I know when you don’t use exec you have to export your environment variables for the sub process to have access to them.

E.g.:

export FOO_VAR=baz
my_process

vs

FOO_VAR=baz
exec my_process

What is the recommended best practice? As we can see, having more than one exec is just wrong, so maybe there should be a linter for that during the build process?


#2

Absolutely exec in run and init hooks. The way this works is that the process started by the supervisor is the run process, and the last exec becomes the process we manage over time.


#3

If there’s no exec, you must reject. Best I’ve got on short notice…


#4

So maybe there should be a check that says “hey, you don’t have an exec in run/init hooks” when you run a build?

Also, I think that should be something called out in the docs?

There is mention for the run hook:

Services run using this hook should do two things:

* Redirect stderr to stdout (e.g. with exec 2>&1 at the start of the hook)
* Call the command to execute with exec <command> <options> rather than running the command directly. This ensures the command is executed in the same process and that the service will restart correctly on configuration changes.

But maybe it should be more prominent? And also mentioned in the init hook.


#5

Also, under what circumstances could you have two processes running? E.g.: if I’m not using exec will restarting the hab sup create a second process?


#6

This isn’t always the case so it’s hard to check for (see the rabbitmq plan)


#7

@elliott-davis isn’t RabbitMQ an exception and not the rule though?

By and large, I think it would be valuable to lint for the 90% and have a “tunable” that allows you to disable certain features.

e.g. build will lint looking for an exec in your run hook. build --no-exec-in-run-hook would disable that check.

This way, we eliminate a gotcha for the majority of users and anyone who isn’t execing probably (hopefully) understands why they are doing it that way and is advanced enough to know to add the --no-exec-in-run-hook (maybe we can come up with a shorter name?) . Or it could be an env var, or a .build.toml var, etc.

It’s like the Rust philosophy “Do everything to make code ‘safe’, but allow sufficiently advanced developers to take the training wheels off”.