4

I have a local postgresql on each machine. I want to run maintenance scripts on shutdown, so users can click "Turn off" and go away while the machine does the maintenance and then actually shutdown when done.

The script must run before postgresql.service stops.

I also want to display a shutdown message informing the user that where will be a maintenance.

I have tried to create a service:

[Unit]
Description=PostgreSQL Maintenance
Requires=postgresql.service
Before=shutdown.target

[Service]
User=postgres
WorkingDirectory=/opt/postgres
ExecStart=/bin/true
ExecStop=/opt/postgres/run-maintenance.sh

[Install]
WantedBy=multi-user.target

and:

[Unit]
Description=PostgreSQL Maintenance
Requires=postgresql.service

[Service]
Type=oneshot
User=postgres
WorkingDirectory=/opt/postgres
ExecStart=/opt/postgres/run-maintenance.sh

[Install]
WantedBy=halt.target shutdown.target

They do not work.

The maintenance script is:

#!/usr/bin/env bash

plymouth display-message --text="Maintenance Message"
psql -d db -f /opt/postgres/maintenance.sql

maintenance.sql

reindex (verbose) database db;
vacuum (full, analyze, verbose);

I have found many similar questions, but did not find a definitive solution.

Thiago Sayão
  • 415
  • 1
  • 5
  • 16

3 Answers3

2

This worked for me:

[Unit]
Description=PostgreSql Maintenance.
After=postgresql.service

[Service]
Type=oneshot
User=postgres
WorkingDirectory=/opt/postgres
ExecStart=/opt/postgres/run-maintenance.sh
TimeoutSec=3600

[Install]
WantedBy=shutdown.target halt.target
Thiago Sayão
  • 415
  • 1
  • 5
  • 16
1

Here's an example of a simple service that performs a task before shutdown. Please note that the default dependencies are disabled by the DefaultDependencies=no option (I guess omission of this configuration is the main reason why your oneshot unit file is not working). As pointed out by other comments, it's probably a good idea to have the RemainAfterExit=yes option too. I also agree with the concerns about timeout made in the comments .

[Unit]
Description=SleepBeforeShutdown Service
DefaultDependencies=no
Before=halt.target shutdown.target reboot.target

[Service]
Type=oneshot
ExecStart=/bin/sleep 30
RemainAfterExit=yes

[Install]
WantedBy=halt.target shutdown.target reboot.target

After editing your service unit file run systemctl enable yourservice.service and reboot. After that, any time you run shutdown, halt or reboot, the type-oneshot service will do its thing first before the system proceeds with actual shutdown/reboot.

Edit
I've now found a previous post where the same solution was offered. I do not have the credits to post comments with a link to the question above, so I'll leave my answer as is (even though, strictly speaking, it's a duplicate) (Moderators, please remove this post if it violates the rules)

Edit 2
And yet another old post with the same answer.

yesno
  • 231
0

Your first attempt is close to correct. My recommendation would be to use a unit with an ExecStop= for commands to run while the system is shutting down, as that's the most reliable way to do so and it's easy to get the ordering right.

One important point is to use Type=oneshot and RemainAfterExit=yes, that ensures your unit will be "started" and stay in that state until the system goes down. Once it starts to go down, it will consider your unit as one of the units to stop and will execute the ExecStop= command on it.

Regarding dependencies, you set them regarding starting up the unit, so you state everything that needs to be up when your unit gets started. When the system goes down, dependencies are stopped in the inverse order, so if you want PostgreSQL to be up while your unit stops, you need an After= dependency on it.

You don't need any dependencies on shutdown, etc. since this is just like a normal unit (starts on boot, or starts manually while the system is running, stops on shutdown as all other units are stopped as well.)

Putting it all together:

[Unit]
Description=PostgreSQL Maintenance
After=postgresql.service

[Service]
Type=oneshot
RemainAfterExit=yes
User=postgres
WorkingDirectory=/opt/postgres
ExecStart=/bin/true
ExecStop=/opt/postgres/run-maintenance.sh
TimeoutSec=3600

[Install]
WantedBy=multi-user.target
filbranden
  • 2,861