2

Suppose that I want my server to sleep on any HTTP request to the path /sleep (i.e. http://hostname/sleep), but also send a complete response (HTTP 200) before sleeping.

Using nginx with FastCGI, I have configured the path in the nginx configuration:

location /sleep {
    fastcgi_pass unix:/path/to/fcgiwrap.socket;
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME /path/to/script.sh;
}

This invokes the following script (/path/to/script.sh):

#!/bin/sh
# -*- coding: utf-8 -*-
cat << EOF
Content-Type: text/html

<html><head><title>Sleep</title><meta charset="UTF-8"></head>
<body><p>Sleep: $(date)</p></body></html>
EOF
sleep 1 && sudo systemctl suspend < /dev/null > /dev/null 2>&1 &

Even though this will sleep the system, FastCGI will block until the child process completes, meaning that the web request will not complete before the system sleeps. So, how do I detach that final command from oversight by FastCGI so that the response completes, yet the command continues in the background, in this case ultimately to sleep the system?

palswim
  • 4,919
  • 6
  • 37
  • 53
  • It shouldn't matter whether I use **nginx** or Apache, so I am not looking for an **nginx**-specific solution like setting the request timeout shorter than the script wait time (i.e. `sleep 5` in the script, but kill the request after 2 seconds). – palswim Jun 05 '21 at 05:54

2 Answers2

1

You could decouple the cgi and the suspend by interposing a file used as a systemd trigger. See man systemd.path for this path-based activation of a unit. It has the advantage of not needing to use sudo from the cgi.

Create a unit file /etc/systemd/system/mycgitrigger.path

[Path]
PathModified=/some/writeable/file
[Install]
WantedBy=multi-user.target

and enable it. Change the cgi script to simply write anything into the file /some/writeable/file in order to trigger the shutdown. Put the short timeout and shutdown command in a unit file /etc/systemd/system/mycgitrigger.service (which does not need to be enabled).

meuh
  • 49,672
  • 2
  • 52
  • 114
  • 1
    For people who have familiarity with Systemd, they probably don't need the obvious tip that to have this work immediately, before the next boot, you must start the `.path` Unit explicitly (`systemctl start mycgitrigger.path`). – palswim Jun 08 '21 at 00:19
0

The obvious solution would be

echo "sleep 1 && sudo systemctl suspend" | at now
symcbean
  • 5,008
  • 2
  • 25
  • 37