What is the typical way to check if a service is running, and if not running start it?
I have an idea for an app I want to build for myself, but it requires things like a database and a couple other small services. What's the best way to check if a service is running, check if it's responding correctly and if not working correctly, stop it and start it again, or if not running, start it?
Application will run on Linux only.
It's best to just require that the service be already running, and handle and report errors arising out of missing services.
By the way, if you are writing an application, you should likely avoid client-server databases and just go with one that stores the data in a conventional file (like SQLite).
Why should I avoid a client server database?
I personally really don't like messing with SQLite in Rust. Sled does look promising though.
Because it's unnecessary if you only access it from one process / one physical computer, and it has several disadvantages:
- As you observed yourself, setting up the DB server process is yet another annoying thing to worry about.
- The file format of client-server DBs is usually neither stable nor portable. Upgrading DB versions often means having to perform a database dump and re-import it again.
- Due to the mediating network connection, every query will be slower, unconditionally.
What's messy about SQLite? It's one of the best-designed in-process databases ever.
Indeed, except that it's not full a database in itself. It's a storage solution that can be a low-level part of a database, but its API is not more than a persistent key-value store. You would need to write the complete DB logic on top of it if you were to store structured (e.g. relational or hierarchical) data in the database.
I've used it with Python in the past and really liked it. I just really had a difficult time efficiently using it in Rust. As a solution in general, I don't see any real issues. It's probably the most used database, if it's not it has to be close. There has to be a reason for that.
So the answer is:
Don't do it?
Generally you leave this sort of to external tools, e.g. systemd on Linux. For example you could configure your database server using a service file with socket activation, so that your database server is automatically started when your application attempts to connect to it.
On the application side you generally assume that your necessary services will be ready, and just try to connect to them.
I really wanted this whole process to be automated in program. I really don't want a dozen different tools that need to be handled by some person. I should be able to check logs if things go really awry, but in general I need it to be one touch; start this program on startup and trust that 99% will be handled in program.
I know stuff like this is done in Python all the time. I don't know Python, nor do I want to learn it right now, but I've seen tons of videos and have friends that script seemingly everything under the sun. Checking for an active service and automating it's start, restart, etc and logging the events doesn't seem like it's out of reach for Rust.
Well you can use something like std::process or std:process:command for more fine grained control over spawning new processes and interacting with them.
There is even a crate that implements even more functionality on top of std::process called interprocess. It is well maintained and specializes exactly on interprocess communication in different operating systems.
Otherwise you can always go for the containerized approach and build one container for the app and one container for the database, then manage them via docker-compose.
If you want to start both an application and a database, another option is to use docker-compose. I use docker-compose to start my application, a Postgres db, and a http reverse proxy. Docker will restart them if one dies, can send logs to a central location, etc.
Can you provide an example of someone doing what you want in Python? Then we might have a better idea of what you mean. It could be that
std::process is what you want. Starting a database that way would be pretty unusual. In my experience databases are usually started by init systems like systemd or in a container.
It looks like, as many of you have suggested,
std::process is what I need.
At the end of the day, I may end up using Docker as well, but I really do want my program to be 'aware' of the status of everything it needs.
Thank you for the guidance.