2018-10-21 Cro as a Service?

I ran Oddmuse 6 for a while now from a little shell script. It set up the environment variables, it checked whether the process was already running, it used nohup to run perl6 service.p6, it saved the PID in a file, and so on. But it didn’t use cro run. And I still don’t know how to do it.

I would like to use cro run because I feel that’s what I need to do in the future when I run multiple sites in parallel. So let’s try this:

#!/bin/bash
export ODDMUSE_MENU="Home, Changes, About"
export ODDMUSE_QUESTION="Name a colour of the rainbow."
export ODDMUSE_ANSWER="red, orange, yellow, green, blue, indigo, violet"
export ODDMUSE_SECRET="rainbow-unicorn"
export ODDMUSE_HOST="next.oddmuse.org"
export ODDMUSE_PORT=20000

cd $HOME/oddmuse6
cro run

This script doesn’t work. All I see is this:

▶ Starting oddmuse6 (oddmuse6)
🔌 Endpoint HTTP will be at http://localhost:20000/
♻ Restarting oddmuse6 (oddmuse6)
♻ Restarting oddmuse6 (oddmuse6)
♻ Restarting oddmuse6 (oddmuse6)
♻ Restarting oddmuse6 (oddmuse6)
♻ Restarting oddmuse6 (oddmuse6)

If I replace cro run with perl6 service.p6, it works.

So now I’m back to this:

#!/bin/bash
export ODDMUSE_MENU="Home, Changes, About"
export ODDMUSE_QUESTION="Name a colour of the rainbow."
export ODDMUSE_ANSWER="red, orange, yellow, green, blue, indigo, violet"
export ODDMUSE_SECRET="rainbow-unicorn"
export ODDMUSE_HOST="next.oddmuse.org"
export ODDMUSE_PORT=20000

cd $HOME/oddmuse6
test -f pid && kill $(cat pid)
perl6 service.p6 &
echo $! > pid

Any ideas?

The service.p6 file is simple:

use Cro::HTTP::Log::File;
use Cro::HTTP::Server;
use Oddmuse::Routes;

my $logs   = open 'access.log'.IO, :w;
my $errors = open 'error.log'.IO,  :w;

my Cro::Service $http = Cro::HTTP::Server.new(
    http => <1.1>,
    host => %*ENV<ODDMUSE_HOST> ||
        die("Missing ODDMUSE_HOST in environment"),
    port => %*ENV<ODDMUSE_PORT> ||
        die("Missing ODDMUSE_PORT in environment"),
    application => routes(),
    after => [Cro::HTTP::Log::File.new(logs => $logs, errors => $errors)]
);
$http.start;
$logs.say: "Listening at http://%*ENV<ODDMUSE_HOST>:%*ENV<ODDMUSE_PORT>";
react {
    whenever signal(SIGINT) {
        $logs.say: "Shutting down...";
        $http.stop;
        done;
    }
    whenever signal(SIGHUP) {
        $logs.say: "Ignoring SIGHUP...";
    }
}

Oddmuse::Routes is available from the Oddmuse 6 repo.

Hm, what could be the problem? Let’s look at the files:

  total 80
  drwxr-xr-x  6 alex alex 4096 Oct 21 11:40 .
  drwxr-xr-x 57 alex alex 4096 Oct 21 11:57 ..
  -rw-r--r--  1 alex alex  205 Oct  7 18:42 .cro.yml~
  -rw-r--r--  1 alex alex  479 Oct  7 19:23 .cro.yml
  -rw-r--r--  1 alex alex   10 Oct  7 18:42 .dockerignore
  -rw-r--r--  1 alex alex   52 Oct  7 18:42 .gitignore
  -rw-r--r--  1 alex alex  221 Oct  7 18:42 Dockerfile
  -rw-r--r--  1 alex alex  471 Oct  7 18:42 META6.json
  -rw-r--r--  1 alex alex  473 Oct  7 18:42 README.md
  -rw-r--r--  1 alex alex   43 Oct 21 11:49 access.log
  drwxr-xr-x  2 alex alex 4096 Oct 17 10:59 css
  -rw-r--r--  1 alex alex    0 Oct 21 11:49 error.log
  drwxr-xr-x  3 alex alex 4096 Oct  7 19:24 lib
  -rw-------  1 alex alex  445 Oct 21 11:46 nohup.out
  -rw-r--r--  1 alex alex    6 Oct 21 11:49 pid
  -rwxr-xr-x  1 alex alex  149 Oct 15 10:43 run.sh~
  -rwxr-xr-x  1 alex alex  318 Oct 15 10:46 run.sh
  -rw-r--r--  1 alex alex  683 Oct 21 11:19 service.p6~
  -rw-r--r--  1 alex alex  779 Oct 21 11:49 service.p6
  drwxr-xr-x  2 alex alex 4096 Oct 10 20:40 templates
  drwxr-xr-x  4 alex alex 4096 Oct 11 08:32 wiki

error.log and access.log are the obvious culprits! Changes in the log file will case cro to restart. So what I’m going to do is move the log files intoa logs subdirectory and add that to the ignore section in .cro.yml.

OK, so that works. I still feel strange using nohup, though.

Shell script:

#!/bin/bash
export ODDMUSE_MENU="Home, Changes, About"
export ODDMUSE_QUESTION="Name a colour of the rainbow."
export ODDMUSE_ANSWER="red, orange, yellow, green, blue, indigo, violet"
export ODDMUSE_SECRET="rainbow-unicorn"
export ODDMUSE_HOST="next.oddmuse.org"
export ODDMUSE_PORT=20000

cd $HOME/oddmuse6

# test -f pid && kill $(cat pid)
# perl6 service.p6 &
# echo $! > pid

nohup cro run &

Service:

use Cro::HTTP::Log::File;
use Cro::HTTP::Server;
use Oddmuse::Routes;

my $logs   = open 'logs/access.log'.IO, :w;
my $errors = open 'logs/error.log'.IO,  :w;

my Cro::Service $http = Cro::HTTP::Server.new(
    http => <1.1>,
    host => %*ENV<ODDMUSE_HOST> ||
        die("Missing ODDMUSE_HOST in environment"),
    port => %*ENV<ODDMUSE_PORT> ||
        die("Missing ODDMUSE_PORT in environment"),
    application => routes(),
    after => [Cro::HTTP::Log::File.new(logs => $logs, errors => $errors)]
);
$http.start;
$logs.say: "Listening at http://%*ENV<ODDMUSE_HOST>:%*ENV<ODDMUSE_PORT>";
react {
    whenever signal(SIGINT) {
        $logs.say: "Shutting down...";
        $http.stop;
        done;
    }
    whenever signal(SIGHUP) {
        $logs.say: "Ignoring SIGHUP...";
    }
}

Me ignoring SIGHUP in the service now has no effect because cro doesn’t ignore SIGHUP which is why the nohup wrapper is needed.

OK, so now my shell script starts nohup cro run & because cro doesn’t daemonize itself. I guess I still find that surprising. And I wonder about the trade-offs. So the benefit is automatic restarts? I also see now that using cro run gives me two moar processes (one runs cro, the other runs my process, moar being the virtual machine this Perl 6 runs on).

If there’s nothing else that I’m missing, perhaps running the service using perl6 directly instead of via cro isn’t such a bad idea after all. I think I’ll do that.

Tags:

Comments

As a user I’m expecting a working systemd file provided. Systemd can solve some of these problems and more.

– AlexDaniel 2018-10-22 12:29 UTC


If you have more information for what you’d need, I’d love to hear it. Sadly, the only systemd thing I ever did was my backup solution...

– Alex Schroeder 2018-10-22 12:35 UTC


Thanks for pointing me at this gist.

NoNewPrivileges=yes
ProtectSystem=strict
ProtectHome=read-only
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectControlGroups=yes
RestrictRealtime=yes
PrivateTmp=yes
PrivateDevices=yes
PrivateUsers=yes

Other things you mentioned in IRC:

MemoryMax and TasksMax should be used. Restart=always and RestartSec=2 is fine. Watchdog needs to be implemented.

– Alex Schroeder 2018-10-22 12:47 UTC


Please make sure you contribute only your own work, or work licensed under the GNU Free Documentation License. Note: in order to facilitate peer review and fight vandalism, we will store your IP number for a number of days. See Privacy Policy for more information. See Info for text formatting rules. You can edit the comment page if you need to fix typos. You can subscribe to new comments by email without leaving a comment.

To save this page you must answer this question:

Please say HELLO.

Referrers: Weekly changes in and around Perl 6