After=
only ensures that the service starts after the other service, if both services are activated.
If you want to have a real dependency to mariadb you have to use Requires=
or Wants=
. This defines the following behavior:
- if you activate gammu-smsd, mariadb will also get activated
- if gammu-smsd is starting and mariadb isn't running, it will be
started for you
- if mariadb gets stopped and gammu-smsd is running, it will be stopped for you
Usually you will still want to use After=
, because Require=
and Wants=
don't ensure order. If you only use Requires=
or Wants=
gammu-smsd may be started in parallel or before mariadb.
If you use Require=
and After=
gammu-smsd won't get started if mariadb fails to start. Where asWants=
still will get gammu-smsd started, if mariadb fails to start. The author of the gammu-smsd RPM probably put the After for both mariadb and postgresql there, so that you can choose between one, both or none of them by activating the appropriate services.
In practice you don't necessarily need to add the Requires=
or Wants=
line to the gammu-smsd configuration. Just make sure that mariadb is activated.
Your problem is probably, that mariadb successfully entered the running state but still isn't ready to accept connections. At least on RHEL mariadb is configured as Type=simple
that means it immediately enters the running state as soon as the mariadb process is started, even though it isn't accepting connections yet.
One simple and hacky way to deal with that would be to simply add a short delay to the start of gammu-smsd with:
ExecStartPre=/bin/sleep 30
A more advanced way would be to use something like this: https://github.com/vishnubob/wait-for-it.
For more information you should read the man pages for systemd.unit and systemd.service.
Type=
Configures the process start-up type for this service unit. One of simple, exec, forking, oneshot, dbus, notify or idle:
If set to
simple (the default if ExecStart= is specified but neither Type= nor
BusName= are), the service manager will consider the unit started
immediately after the main service process has been forked off. It is
expected that the process configured with ExecStart= is the main
process of the service. In this mode, if the process offers
functionality to other processes on the system, its communication
channels should be installed before the service is started up (e.g.
sockets set up by systemd, via socket activation), as the service
manager will immediately proceed starting follow-up units, right after
creating the main service process, and before executing the service's
binary. Note that this means systemctl start command lines for simple
services will report success even if the service's binary cannot be
invoked successfully (for example because the selected User= doesn't
exist, or the service binary is missing).
Requires=
Configures requirement dependencies on other units. If this unit gets
activated, the units listed here will be activated as well. If one of
the other units fails to activate, and an ordering dependency After=
on the failing unit is set, this unit will not be started. Besides,
with or without specifying After=, this unit will be stopped if one of
the other units is explicitly stopped. This option may be specified
more than once or multiple space-separated units may be specified in
one option in which case requirement dependencies for all listed names
will be created. Note that requirement dependencies do not influence
the order in which services are started or stopped. This has to be
configured independently with the After= or Before= options. If a unit
foo.service requires a unit bar.service as configured with Requires=
and no ordering is configured with After= or Before=, then both units
will be started simultaneously and without any delay between them if
foo.service is activated. Often, it is a better choice to use Wants=
instead of Requires= in order to achieve a system that is more robust
when dealing with failing services.
Note that this dependency type does not imply that the other unit
always has to be in active state when this unit is running.
Specifically: failing condition checks (such as ConditionPathExists=,
ConditionPathIsSymbolicLink=, … — see below) do not cause the start
job of a unit with a Requires= dependency on it to fail. Also, some
unit types may deactivate on their own (for example, a service process
may decide to exit cleanly, or a device may be unplugged by the user),
which is not propagated to units having a Requires= dependency. Use
the BindsTo= dependency type together with After= to ensure that a
unit may never be in active state without a specific other unit also
in active state (see below).
Note that dependencies of this type may also be configured outside of
the unit configuration file by adding a symlink to a .requires/
directory accompanying the unit file. For details, see above.
Wants=
A weaker version of Requires=. Units listed in this option will be
started if the configuring unit is. However, if the listed units fail
to start or cannot be added to the transaction, this has no impact on
the validity of the transaction as a whole. This is the recommended
way to hook start-up of one unit to the start-up of another unit.
Note that dependencies of this type may also be configured outside of
the unit configuration file by adding symlinks to a .wants/ directory
accompanying the unit file. For details, see above.
Before=, After=
These two settings expect a space-separated list of unit names. They
configure ordering dependencies between units. If a unit foo.service
contains a setting Before=bar.service and both units are being
started, bar.service's start-up is delayed until foo.service has
finished starting up. Note that this setting is independent of and
orthogonal to the requirement dependencies as configured by Requires=,
Wants= or BindsTo=. It is a common pattern to include a unit name in
both the After= and Requires= options, in which case the unit listed
will be started before the unit that is configured with these options.
This option may be specified more than once, in which case ordering
dependencies for all listed names are created. After= is the inverse
of Before=, i.e. while After= ensures that the configured unit is
started after the listed unit finished starting up, Before= ensures
the opposite, that the configured unit is fully started up before the
listed unit is started. Note that when two units with an ordering
dependency between them are shut down, the inverse of the start-up
order is applied. i.e. if a unit is configured with After= on another
unit, the former is stopped before the latter if both are shut down.
Given two units with any ordering dependency between them, if one unit
is shut down and the other is started up, the shutdown is ordered
before the start-up. It doesn't matter if the ordering dependency is
After= or Before=, in this case. It also doesn't matter which of the
two is shut down, as long as one is shut down and the other is started
up. The shutdown is ordered before the start-up in all cases. If two
units have no ordering dependencies between them, they are shut down
or started up simultaneously, and no ordering takes place. It depends
on the unit type when precisely a unit has finished starting up. Most
importantly, for service units start-up is considered completed for
the purpose of Before=/After= when all its configured start-up
commands have been invoked and they either failed or reported start-up
success.
ExecStartPre=, ExecStartPost=
Additional commands that are executed before or after the command in
ExecStart=, respectively. Syntax is the same as for ExecStart=, except
that multiple command lines are allowed and the commands are executed
one after the other, serially.
If any of those commands (not prefixed with "-") fail, the rest are
not executed and the unit is considered failed.
ExecStart= commands are only run after all ExecStartPre= commands that
were not prefixed with a "-" exit successfully.
ExecStartPost= commands are only run after the commands specified in
ExecStart= have been invoked successfully, as determined by Type=
(i.e. the process has been started for Type=simple or Type=idle, the
last ExecStart= process exited successfully for Type=oneshot, the
initial process exited successfully for Type=forking, "READY=1" is
sent for Type=notify, or the BusName= has been taken for Type=dbus).
Note that ExecStartPre= may not be used to start long-running
processes. All processes forked off by processes invoked via
ExecStartPre= will be killed before the next service process is run.
Note that if any of the commands specified in ExecStartPre=,
ExecStart=, or ExecStartPost= fail (and are not prefixed with "-", see
above) or time out before the service is fully up, execution continues
with commands specified in ExecStopPost=, the commands in ExecStop=
are skipped.