Description
I propose -d/--detach flag to ipfs daemon command to automatically fork and detach the process after it is ready to serve. The parent process should take care of the initialization and any reporting on the STDOUT before detaching the child, if successful, and report any issues if unsuccessful. This has been discussed briefly in #5983.
This is often desired to wait for the daemon to be ready before executing any dependent processes. Current workaround is to run the process in background (i.e., using & suffix in *nix environment) and observe the process using an external utility, which is neither ideal nor robust enough, and requires adding boilerplate code in many applications to do the same thing.
For example, in IPWB we do the following:
# Run the IPFS daemon in background, initialize configs if necessary
ipfs daemon --init &
# Wait for IPFS daemon to be ready
while ! curl -s localhost:5001 > /dev/null
do
sleep 1
done
This mostly works, but had some quirks:
- It relies on an external tool, in this case,
curl - It hard-codes the port number (making it configurable/dynamic will make the script more complex)
- It introduces a quantized duration of sleep (i.e., multiples of one second in this case), rather than moving on immediately, making the value smaller means probing it with the external tool more often
- The biggest flaw of this process is that it expects that the daemon will eventually be ready, which, if it fails, the loop will keep probing forever
This mostly works for us because we are running this whole process in an isolated container where external factors causing failure or collisions are minimal, but others may not have the same luxury.
@Stebalien suggests a workaround in #5983:
So... the most correct way to do this is to wait for the string "Daemon is ready" on stdout.
However, this approach has some drawbacks. Relying on such string matching is a dangerous proposition as it is brittle. For example, if in a future release, IPFS daemon decides that the phrase can be improved, which is not an unlikely scenario, then application relying on this will start to break. Unixy way of checking status of a process is status codes, not returned messages.
Here is another situation that I encountered recently when creating the IPFS Setup Action to be used in GitHub Workflows CI:
await exec.exec('ipfs', ['init'], opts)
if (runDaemon) {
const daemon = cp.spawn('ipfs', ['daemon'], {detached: true, stdio: 'ignore'})
daemon.unref()
let attemptsLeft = MAXATTEMPTS
while (--attemptsLeft) {
try {
await exec.exec('curl', ['-s', '-X', 'POST', IPFSAPI])
break
} catch (error) {
await sleep(1000)
}
}
if (!attemptsLeft) {
throw new Error('IPFS API service unreachable')
}
}
This time, I did not want to wait forever, so I added a hard limit on how many maximum tries it would make to probe the IPFS daemon status. However, when spawning the process in NodeJS, I had to set stdio to ignore, otherwise the parent process will continue to wait even after the child is detached. As a side-effect, now I cannot read STDOUT of the daemon, which, if I could, I would have set some output variables (such as reported connection information and URIs) that could be useful in the following steps of the workflow pipeline.
@Stebalien suggested --wait or --fork flags for this, which are equally as appropriate, but I have seen -d/--detach to be more commonly used for this purpose (e.g., in docker container run).