OpenSUSE: why does "service ... start" always stop my application? - opensuse

I am running OpenSUSE LEAP 15. I am trying to define an application as service such that I can start/stop it using service <servicename> start or service <servicename> stop, resp. and also to restart it automatically on a system restart.
But for some odd reason this doesn't work! My application never runs after a service <servicename> start :-(
The <servicename>.service file that I defined in /usr/lib/systemd/system contains the two commands:
...
ExecStart=/opt/zhquest/current/ctlscript.sh start
ExecStop=/opt/zhquest/current/ctlscript.sh stop
...
When I call the script manually, i.e. when I enter ctlscript.sh start or ctlscript.sh stop then the application starts and stops fine as it should.
But - as I found out by adding echo statements to the script - when I issue a service <servicename> start then the script is actually called twice, first with the argument start and then again with the argument stop. Naturally the application then does not run, since it gets stopped again immediately after it got started.
Why is that so??? Why does the service command call my ctlscript.sh twice, first with argument start and then again with argument stop when I enter service <servicename> start? That seems completely absurd!

Just for the benefit of anyone stumbling over this thread:
I found the answer for my problem here: https://superuser.com/questions/1022142/why-is-systemd-stopping-service-immediately-after-it-is-started
In short: If the application being called to start the application is actually a control script which itself terminates after having done its job of starting (i.e. forking) the application (as is the case here - ctlscript.sh is exactly such a script) then the service type needs to be of Type=forking (and not Type=simple as I had specified since I had simply copied the service-file from another .service-file and only replaced the ExecStart=... and ExecStop=...-values.
Since the started script ends systemd "thinks" that the started application has crashed and immediately executes a subsequent stop-command with the intention to clean up after a crashed applicaiton start.
Here, however, it's normal that the script terminates after having done its job and that is signaled with the ...=forking-option.

Related

Using boost::process to completely detach a process

I have a systemd service which runs and does its thing. Periodically I need it to upgrade itself, which requires a shutdown and a restart of the service. For question purposes the upgrade script can be as simple as:
echo "Stopping service..."
systemctl stop myservice
echo "Doing some stuff..."
sleep 10s
echo "Starting service..."
systemctl start myservice
I want to call this within the service itself, preferably using boost::process:
boost::process::child instexe{
boost::process::search_path("bash"),
std::vector<std::string>{"installerscript.sh"},
boost::process::start_dir("/installer/folder"),
boost::process::std_out > "/some/log/file.txt"
};
instexe.detach();
The problem is that as soon as the script calls systemctl stop myservice, the installer script is killed.
Is there a way I can do what I want to do with boost::process? Or how can I do it?
If the upgrades are at predefined period you can think of using crontab.
https://opensource.com/article/17/11/how-use-cron-linux
00 09-17 * * 1-5 /usr/local/bin/installerScript.sh
The above entry in crontab will make the program upgrade every hour between 9 am to 5pm from Monday to Friday. There are many combinations that you can think and configure.
Is there a way I can do what I want to do with boost::process? Or how can I do it?
If you have the child process killing the parent, there's always going to be a race condition by definition.
The quick hack is to put a sleep statement at the start of the installer script, but the correct solution is to explicitly synchronize with the child:
have the installer script detect whether it's running interactively (ie, being run manually from a terminal instead of by your service)
if it is non-interactive (your use case), have it wait for some input in stdin
connect the stdin pipe when you create the child
detach the child and then write something to tell the child it's safe
Other synchronization mechanisms are available, you could use a lockfile or a signal - you just need to make sure the child doesn't do anything until after the parent has detached it.
I turns out (from this question, which leads to the excellent-but-unfindable systemd.kill manpage) that systemd has four different ways of stopping a unit, controlled by the KillMode variable in your unit configuration:
control-group will send SIGTERM (by default, overridable with KillSignal) to every process in the unit's cgroup. That means both parent and child.
mixed will send SIGTERM (or KillSignal) to your main process and SIGKILL to the child.
process will kill only the main process and leave the child alone
none is not recommended, it will just run your ExecStop procedure
You can probably just set KillMode=process, but note that if SendSIGKill or SendSIGUP are true, those signals will still be delivered to your child after TimeoutStopSec.
It seems like it might be simpler to restart your service and have a launch script that can update it at startup, or to perform the update in your ExecStop procedure, than to persuade systemd to leave the child alone until the update is complete, without the risk of a hung child updater hanging around forever.
Either way, your remaining problems are exclusively with systemd rather than with boost.Process.

Applescript command encountering error after closing chrome window

So I have been working on a project to mess around with some of my coding friends. I am trying to make an AppleScript application that tells Chrome to go back a page when run and I want it to run all the time. I have had to base it off of whether or not chrome has an active window open or not, I managed to get it to work so far but when I put in the repeated "Go back" command it comes up with an error message saying can't get window 1.
This is the code I am using. I am using High Sierra if that makes a difference.
repeat
if application "Google Chrome" is running then
repeat
tell application "Google Chrome"
if exists (window 1 of application "Google Chrome") then
repeat while exists (window 1 of application "Google Chrome")
go back tab of window 1
end repeat
end if
end tell
end repeat
end if
end repeat
No. This is not how to implement a stay-open script. Doing endless repeat loops with no means of exiting them is just going to devour system resources and make Google Chrome unusable until the script is forced to quit.
Also, the code is horrific: lots of redundant statements and confusing syntax.
You would better achieve your aim by creating what is called a stay-open application script, which will use the idle handler to process commands every few seconds or so. As the name implies, the script will stay open and execute the commands until you tell it to quit.
Start by declaring a property that determines how often the idle handler is called. This is defined at the bottom, following a run handler, which executes upon running of the script and calls the idle handler.
property idleTime : 20 --seconds
on run
idle
end run
on idle
tell application "Google Chrome"
if it is not running then return idleTime
tell window 1 to if it exists then ¬
tell its active tab
if its URL contains "disney" then ¬
tell me to quit
set its URL to "chrome://newtab/"
end tell
end tell
return idleTime
end idle
I slightly modified the joke you're pulling on your friends, because go back will only work so many times before you reach the end of the history and there's no further back one can go. Instead, I told the tab to load up the New Tab starting page every 20 seconds, which I'm sure will be very confusing for the user.
In order to get it up and running properly, you need to save the script as an Application, and check the box that marks it as a stay open script. Then simply double click to run it.
There are two ways to terminate this script: ① Open Activity Monitor and terminate its process from the list of running processes; or ② Visit Disney.com (or any Disney website) in Chrome and wait 20 seconds.
Simply save this code as a stay open application.
on idle
tell application "Google Chrome"
if it is not running then return 10 -- seconds to wait before repeating
tell window 1 to if it exists then ¬
try
go back active tab
end try
end tell
return 10 -- seconds to wait before repeating
end idle

Restarting a linux daemon

I have Linux daemon that I have written in C++ that should restart itself when given a "restart"-command from a user over the network through its console. Is this possible? I use a /etc/init.d script. How can I program it to restart itself? Should I launch a new process with a very long delay (one minute) that then fires the shell script again ? Problem is that the daemon may take a very long time to close down and it could take even more than a minute in a worst-case scenario.
There are basically three ways for an application to restart itself:
When the application is told to restart, it does proper clean-up, releases all resources it has allocated, and then re-initializes like it was started from scratch.
Fork a new process, where the new child process execs itself and the parent process exits normally.
The daemon is actually just a wrapper application, much like an init-script. It forks a new process which runs the actual application, while the parent process just waits for it to exit. If the child process (and the real application) returns with a special exit-code, it means that it should be restarted so the forks/execs all over again.
Note that points 2 and 3 are basically the same.
Break down the restart as two steps, stop and start. if your program takes time to stop, it should be handled in the stop function, I can't comment on specifics since I don't know your usecase, but I'd imagine monitoring the process to check if it's terminated will be a graceful way to stop
Do whatever shut-down/clean-up you need to do, then call this:
execl( argv[0], argv, reinterpret_cast< char* >( 0 ) );
Just like fork() and exec(), but skipping the fork. The exec will replace the current process with a new copy of itself. cf. http://linux.die.net/man/3/exec
Your init script should just kill your daemon and start it again. Don't try to restart your daemon FROM your daemon.

C++ Having Windows Service Start another Program

Is it possible to create a windows service to create and maintain another process? Like I'm writing a program, and say a virus killed the process, could I have my window service running and basically 'watching' it? I already have the code for a regular application that stays running and executes a program if it's not currently running, to keep it running.
I've never written a service before, but would it be that hard to just write this simple program, which basically runs a check to see if the process is running, if not, it executes it and sleeps for a few minutes?
Thanks.
Yes, it is possible. It is not uncommon to see third-party apps have watchdog services to keep them running in case of crashes. A service can enumerate running processes using EnumProcesses(), and if the desired executable is not running then start a new copy of it using CreateProcessAsUser().
If the service is the one starting the executable process in the first place, or can find it after an enumeration, one optimization would be to keep an open handle to the process (returned by CreateProcess...(), or use OpenProcess() on the process ID an enumeration returns), and then use a wait function, like WaitForSingleObject(), to detect when the process stops running. That way, you don't have to enumerate processes to find out if the intended process is still running or not.

C++ executing a bash script which terminates and restarts the current process

So here is the situation, we have a C++ datafeed client program which we run ~30 instances of with different parameters, and there are 3 scripts written to run/stop them: start.sh stop.sh and restart.sh (which runs stop.sh and then start.sh).
When there is a high volume of data the client "falls behind" real time. We test this by comparing the system time to the most recent data entry times listed. If any of the clients falls behind more than 10 minutes or so, I want to call the restart script to start all the binaries fresh so our data is as close to real time as possible.
Normally I call a script using System(script.sh), however the restart script looks up and kills the process using kill, BUT calling System() also makes the current program execution ignore SIGQUIT and SIGINT until system() returns.
On top of this if there are two concurrent executions with the same arguments they will conflict and the program will hang (this stems from establishing database connections), so I can not start the new instance until the old one is killed and I can not kill the current one if it ignores SIGQUIT.
Is there any way around this? The current state of the binary and missing some data does not matter at all if it has reached the threshold, I also can not just have the program restart itself, since if one of the instances falls behind, we want to restart all 30 of the instances (so gaps in the data are at uniform times). Is there a clean way to call a script from within C++ which hands over control and allows the script to restart the program from scratch?
FYI we are running on CentOS 6.3
Use exec() instead of system(). It will replace your process with the new one. Note there is a significant different in how exec() is called and how it behaves: system() passes its string argument to the system shell to run. exec() actually executes an executable file, and you need to supply the arguments to the process one at a time, instead of letting the shell parse them apart for you.
Here's my two cents.
Temporary solution: Use SIGKILL.
Long-term solution: Optimize your code or the general logic of your service tree, using other system calls like exec or by rewritting it to use threads.
If you want better answers maybe you should post some code and or degeneralize the issue.