Skip to content

Conversation

@whitslack
Copy link
Contributor

When other initscripts depend on bitcoind, it's because their daemons want to be able to invoke bitcoin-cli or to communicate with bitcoind via RPC. That can't happen until some time after bitcoind has forked into the background. The -startupnotify option was added in 090530c (#15367) to support exactly this use case, so let's use it.

The ideal OpenRC mechanism of marking the service inactive at startup and later calling back into the start() function with IN_BACKGROUND=yes won't work here because bitcoind runs as an unprivileged user that is not allowed to call rc-service ${SVCNAME} start, and OpenRC has no mechanism like systemd-notify, so instead we make start-stop-daemon lock a startup dummy file with flock(1) before exec'ing bitcoind, and then we use -startupnotify to release the lock when bitcoind is ready to service RPC requests. In the initscript's start_post() function we lock the startup file briefly, which forces that function to wait until bitcoind has released its lock on the file, which will happen when bitcoind either executes the -startupnotify command or dies. After acquiring and releasing the lock, start_post() performs one final check that the pid file still exists, which allows the service to be marked as started or stopped appropriately.

When other initscripts depend on bitcoind, it's because their daemons
want to be able to invoke bitcoin-cli or to communicate with bitcoind
via RPC. That can't happen until some time after bitcoind has forked
into the background. The -startupnotify option was added in 090530c
(bitcoin#15367) to support exactly this use case, so let's use it.

The ideal OpenRC mechanism of marking the service inactive at startup
and later calling back into the start() function with IN_BACKGROUND=yes
won't work here because bitcoind runs as an unprivileged user that
is not allowed to call "rc-service ${SVCNAME} start", and OpenRC has no
mechanism like systemd-notify, so instead we make start-stop-daemon
lock a startup dummy file with flock(1) before exec'ing bitcoind, and
then we use -startupnotify to release the lock when bitcoind is ready
to service RPC requests. In the initscript's start_post() function we
lock the startup file briefly, which forces that function to wait until
bitcoind has released its lock on the file, which will happen when
bitcoind either executes the -startupnotify command or dies. After
acquiring and releasing the lock, start_post() performs one final check
that the pid file still exists, which allows the service to be marked
as started or stopped appropriately.
Copy link
Member

@luke-jr luke-jr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure this is a good idea. If the user starts bitcoind at boot, he will need to wait potentially an annoyingly long time before he can login...?

@whitslack
Copy link
Contributor Author

Not sure this is a good idea. If the user starts bitcoind at boot, he will need to wait potentially an annoyingly long time before he can login...?

The other way I could do it would be to have the initscript mark the service as inactive and fork a subshell process into the background to wait for the lock and eventually reinvoke the initscript (with IN_BACKGROUND=yes) to mark the service as started so any dependent services can start in the background.

That said, if you're using rc_parallel=yes, then I think you'd get a login prompt before BitcoinD has finished starting anyway, assuming your login manager doesn't (transitively) depend on bitcoind, which I can't imagine it would.

@luke-jr
Copy link
Member

luke-jr commented Jun 27, 2021

I've never seen a login prompt before all startup has completed... (console login)

@whitslack
Copy link
Contributor Author

Oh, sure. SystemV init with the default Gentoo config won't start agetty until openrc is finished transitioning to the default runlevel.

So, would you be more amenable to this change if I did the background thing? To be honest, that's how I've had it set up on my machine for years (since long before -startupnotify was implemented), but I assumed the rather gross hackishness of that solution would be more objectionable than the straightforward approach.

@luke-jr
Copy link
Member

luke-jr commented Jun 27, 2021

I'm not familiar enough with the tradeoffs and implementation details, but it sounds like a better solution at face value.

@whitslack
Copy link
Contributor Author

Okay, I'll show you. Might take me a couple days to get to it.

@whitslack
Copy link
Contributor Author

@luke-jr: See #22354.

@DrahtBot
Copy link
Contributor

DrahtBot commented Jun 28, 2021

The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

Conflicts

Reviewers, this pull request conflicts with the following ones:

  • #22354 (contrib/init: (OpenRC) use -startupnotify to wait for startup completion [alternative] by whitslack)

If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

@laanwj
Copy link
Member

laanwj commented Jul 7, 2021

Wouldn't -daemonwait help here? This option was added for doing a similar thing for the systemd script, and seems more straightforward.

@whitslack
Copy link
Contributor Author

Wouldn't -daemonwait help here? This option was added for doing a similar thing for the systemd script, and seems more straightforward.

@laanwj: That's the option I was searching for when I started out on this project, as I was certain I'd seen it mentioned in the Bitcoin Optech newsletter, but it's not listed in --help, so I abandoned that avenue. Thanks for the pointer.

That said, -daemonwait won't address @luke-jr's concern, which I addressed in an alternative way using -startupnotify in #22354.

@laanwj
Copy link
Member

laanwj commented Aug 16, 2021

it's not listed in --help, so I abandoned that avenue. Thanks for the pointer.

Are you sure? It is mentioned in --help here:

  -daemonwait
       Wait for initialization to be finished before exiting. This implies
       -daemon (default: 0)

It's relatively new, so make sure you check with at least 22.x.

@whitslack
Copy link
Contributor Author

It's relatively new, so make sure you check with at least 22.x.

@laanwj: Great! I don't run prerelease versions of Bitcoin Core, so I haven't seen it yet.

Nevertheless, naïvely using -daemonwait doesn't seem to be a good option here, as it would delay the completion of OpenRC's switch to the default runlevel at boot and thus will delay init's startup of agetty/login for longer than may be desirable. Perhaps it would be feasible to start bitcoind with -daemonwait in a backgrounded subshell and call back to OpenRC to mark the service as started after the bitcoind launcher process returns to the subshell. That would address @luke-jr's concern without using -startupnotify.

@whitslack whitslack closed this Jan 14, 2022
@whitslack whitslack deleted the openrc-startupnotify branch January 14, 2022 08:27
@bitcoin bitcoin locked and limited conversation to collaborators Jan 14, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants