Re: [systemd-devel] Starting units when a port is available for connections

2015-05-28 Thread Adam Zegelin

> On 27 May 2015, at 8:40 pm, Andrei Borzenkov  wrote:
> 
> Hmm ... this sounds suspiciously like what D-Bus does. Did you consider
> using D-Bus in your application? 
> 
> But for now there is no way to express such dependency in systemd;
> D-Bus being exception, you can make services dependent on D-Bus end
> points.

I’ve considered it now :) I communicate with systemd via D-Bus for starting & 
stopping services.

How does one write a service unit that depends on a D-Bus endpoint? Is this 
supported by systemd, or is this an application level thing? I’m unable to find 
anything in the systemd docs about creating dependencies on D-Bus endpoints. 


> I wonder - can your master service trigger startup of clients when it is
> ready? Note that it can be done in completely generic way - it can
> simply run something like cassandra.target and you can plug in any
> client into this target.

This is another option that I’ll play with. 

Thanks,
Adam

___
systemd-devel mailing list
systemd-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/systemd-devel


[systemd-devel] Starting units when a port is available for connections

2015-05-27 Thread Adam Zegelin
Hi list,

I’m running Cassandra (C*, a clustered database) as a systemd service. 
Currently this is just a “Type=simple” service, as such, dependant units will 
start as soon as the C* process starts rather than when C* is accepting client 
connections.

I’d like to transition to something more complex so I can start to write 
additional units that depend on C*.

I’ve successfully managed to set the service type to “notify” and modify C* to 
call sd_notify() when is ready to accept client connections.
Further experimentation reveals that this is not an ideal solution. C* can take 
a long time (minutes to _hours_) to reach the point where it will accept client 
connections/queries. The default startup timeout is 90s, which causes the 
service to be marked failed if exceeded, hence C*, with its long startup times, 
will often never get the chance to transition to “active”.


Part of the issue for me is trying to define what “active” means. The man 
pages, for “Type=forking" services, says: "The parent process is expected to 
exit when start-up is complete and all communication channels are set up”. I’m 
assuming for “notify” services, sd_notify() should be called when "start-up is 
complete and all communication channels are set up”. Even if this takes hours?

Cassandra exposes a number of inet ports of interest:
- Client connection ports for running queries via Cassandra Query Language 
(CQL)/Thrift (RPC) — this is what most clients use to query the database (i.e., 
to run `SELECT * FROM …` style queries)
- JMX (Java Management Extensions) for performing management operations — the 
C* and 3rd-party management tools use this to call management functions and to 
collect statistics/metrics about the JVM and C*.

The JMX socket is available a few seconds after the process is running.

The CQL/Thrift ports can take far longer to become available — sometimes hours 
after the process starts. Cassandra only starts listening on these ports once 
it has joined the cluster of nodes & has synchronised its state. State 
synchronisation may require bootstrapping & copying large amounts of data 
across the network and hence take a long time to complete.

Currently my dependent C* client units simply spin-wait, attempting to 
establish a connection to C*. This seems like duplicated effort and makes these 
services more complex than they need to be.

My original thought was to just disable the startup timeout on the C*, but that 
means the unit will stay “activating” for a long time. Also means that JMX 
clients, which can establish connections almost immediately, would have their 
startup deferred unnecessarily.

Ideally I’d like to be able to write units that can depend on individual ports 
being available from a process — i.e, when the CQL port is available, start the 
client unit(s) and when JMX is available, start a monitoring service. Is this 
possible with systemd?

Alternatively, I was thinking that I could write some kind of simple 
process/script that attempts a connection, and exits with failure if the 
connection cannot be established, or success if it can. I’d then write a unit 
file, e.g. `cassandra-cql-port.service`:
[Unit]
# not really sure what combo of 
Wants/Requires/Requisite/BindsTo/PartOf/Before/After is needed
Requisite=cassandra.service

[Service]
Type=oneshot
RemainAfterExit=true
ExecStart=/opt/bin/watch-port 9042
Restart=on-failure
RestartSec=1min
StartLimitInterval=0

My client units could then want/require this unit. Is this a valid approach?

Or am I walking down the wrong path to use systemd to manage this?

Regards,
Adam

___
systemd-devel mailing list
systemd-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/systemd-devel


Re: [systemd-devel] Restarting service starts stopped dependants

2015-02-09 Thread Adam Zegelin

> On 10 Feb 2015, at 6:46 am, Andrei Borzenkov  wrote:
> 
> B is started because C is started so it is not relevant.

Yes, this is expected because B is a dependency of C. Starting C should start B.
I mentioned it because, to me, it was unexpected that /re/starting A caused B 
to start.

> C is started probably due to logic "if A and C are running and you
> restart A you should also restart C". I am not convinced it is the
> right thing to do TBH, but well …

Restarting C as a result of restarting A is correct behaviour to me, but
only if C was already running.

A restart = stop + start in a single transaction, correct?

As such, `systemctl restart A` should:
- Stop A
- Stop C (if it’s running) as C can’t run without A (Requires=A)
- Start A
- Start C, but only if C was previously running.

Starting C only if it was running previously makes sense, because `start` is not
transitive.


> Does patch below help?
> 
> diff --git a/src/core/transaction.c b/src/core/transaction.c
> index b0b3d6b..8901119 100644
> --- a/src/core/transaction.c
> +++ b/src/core/transaction.c
> @@ -1027,7 +1027,7 @@ int transaction_add_job_and_dependencies(
> if (type == JOB_STOP || type == JOB_RESTART) {
> 
> SET_FOREACH(dep, 
> ret->unit->dependencies[UNIT_REQUIRED_BY], i) {
> -r = transaction_add_job_and_dependencies(tr, 
> type, dep, ret, true, override, false, false, ignore_order, e);
> +r = transaction_add_job_and_dependencies(tr, 
> type == JOB_RESTART ? JOB_TRY_RESTART : type, dep, ret, true, override, 
> false, false, ignore_order, e);
> if (r < 0) {
> if (r != -EBADR)
> goto fail;

I will try. I note that TRY_RESTART “… does nothing if units are not running.” 
(systemctl(1)), which is perhaps the solution to the problem.

Regards,
Adam

___
systemd-devel mailing list
systemd-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/systemd-devel


[systemd-devel] Restarting service starts stopped dependants

2015-02-09 Thread Adam Zegelin
Hi list,

Is the following expected behaviour?

Given services A, B, and C.

C "Requires" A & B.

All units are inactive.

`systemctl restart A` activates C, which in turn activates B.
Whereas `systemctl start A` activates A and only A. C and B are left inactive.



I can understand that starting C should start both A and B as they are Required 
dependencies.
But I can’t grasp why *restarting* A should start C, if C is stopped. And then 
by extension why B should start.

See below for example commands & output.

Regards,
Adam


core@core-01 /etc/systemd/system $ find . -maxdepth 1 \( -name A.service -or 
-name B.service -or -name C.service \) -print -exec cat {} \;
./A.service
[Unit]

[Service]
ExecStart=/bin/bash -c 'while true; do echo this is service A; sleep 1; done'

[Install]
WantedBy=multi-user.target


./B.service
[Unit]

[Service]
ExecStart=/bin/bash -c 'while true; do echo this is service B; sleep 1; done'

[Install]
WantedBy=multi-user.target


./C.service
[Unit]

Requires=A.service B.service

[Service]
ExecStart=/bin/bash -c 'while true; do echo this is service C; sleep 1; done'

[Install]
WantedBy=multi-user.target


core@core-01 /etc/systemd/system $ systemctl status --lines=0 A B C
● A.service
Loaded: loaded (/etc/systemd/system/A.service; disabled; vendor preset: 
disabled)
Active: inactive (dead) since Mon 2015-02-09 07:12:45 UTC; 8min ago
Main PID: 20871 (code=killed, signal=TERM)
CGroup: /system.slice/A.service

● B.service
Loaded: loaded (/etc/systemd/system/B.service; enabled; vendor preset: disabled)
Active: inactive (dead) since Mon 2015-02-09 07:12:45 UTC; 8min ago
Main PID: 20867 (code=killed, signal=TERM)
CGroup: /system.slice/B.service

● C.service
Loaded: loaded (/etc/systemd/system/C.service; enabled; vendor preset: disabled)
Active: inactive (dead) since Mon 2015-02-09 07:12:45 UTC; 8min ago
Main PID: 20866 (code=killed, signal=TERM)
CGroup: /system.slice/C.service
core@core-01 /etc/systemd/system $ sudo systemctl restart A
core@core-01 /etc/systemd/system $ systemctl status --lines=0 A B C
● A.service
Loaded: loaded (/etc/systemd/system/A.service; disabled; vendor preset: 
disabled)
Active: active (running) since Mon 2015-02-09 07:21:31 UTC; 1s ago
Main PID: 21196 (bash)
CGroup: /system.slice/A.service
├─21196 /bin/bash -c while true; do echo this is service A; sleep 1; 
done
└─21201 sleep 1

● B.service
Loaded: loaded (/etc/systemd/system/B.service; enabled; vendor preset: disabled)
Active: active (running) since Mon 2015-02-09 07:21:31 UTC; 1s ago
Main PID: 21194 (bash)
CGroup: /system.slice/B.service
├─21194 /bin/bash -c while true; do echo this is service B; sleep 1; 
done
└─21200 sleep 1

● C.service
Loaded: loaded (/etc/systemd/system/C.service; enabled; vendor preset: disabled)
Active: active (running) since Mon 2015-02-09 07:21:31 UTC; 1s ago
Main PID: 21195 (bash)
CGroup: /system.slice/C.service
├─21195 /bin/bash -c while true; do echo this is service C; sleep 1; 
done
└─21202 sleep 1
core@core-01 /etc/systemd/system $ systemctl --version
systemd 218
-PAM -AUDIT -SELINUX +IMA -APPARMOR +SMACK -SYSVINIT +UTMP +LIBCRYPTSETUP 
-GCRYPT -GNUTLS -ACL -XZ -LZ4 +SECCOMP +BLKID -ELFUTILS +KMOD -IDN




core@core-01 /etc/systemd/system $ sudo systemctl stop A B C
core@core-01 /etc/systemd/system $ sudo systemctl start A
core@core-01 /etc/systemd/system $ systemctl status --lines=0 A B C
● A.service
Loaded: loaded (/etc/systemd/system/A.service; disabled; vendor preset: 
disabled)
Active: active (running) since Mon 2015-02-09 07:35:17 UTC; 1s ago
Main PID: 23972 (bash)
CGroup: /system.slice/A.service
├─23972 /bin/bash -c while true; do echo this is service A; sleep 1; 
done
└─23974 sleep 1

● B.service
Loaded: loaded (/etc/systemd/system/B.service; enabled; vendor preset: disabled)
Active: inactive (dead) since Mon 2015-02-09 07:35:13 UTC; 4s ago
Process: 21194 ExecStart=/bin/bash -c while true; do echo this is service B; 
sleep 1; done (code=killed, signal=TERM)
Main PID: 21194 (code=killed, signal=TERM)
CGroup: /system.slice/B.service

● C.service
Loaded: loaded (/etc/systemd/system/C.service; enabled; vendor preset: disabled)
Active: inactive (dead) since Mon 2015-02-09 07:35:13 UTC; 4s ago
Process: 23830 ExecStart=/bin/bash -c while true; do echo this is service C; 
sleep 1; done (code=killed, signal=TERM)
Main PID: 23830 (code=killed, signal=TERM)
CGroup: /system.slice/C.service


___
systemd-devel mailing list
systemd-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/systemd-devel