How can I start my prolog web service using a systemctl service on a linux server?

I’m using: SWI-Prolog version 8.0.3 for x86_64-linux

I want the code to run a prolog web service on a linux server using systemctl.
I created a script that is executed on the server’s start, however the web service is being halted automatically after it starts.

I have a prolog file (prolog.pl) and the script file (prolog_init.sh) located at /home/username/

My code looks like this:

prolog.pl

:- use_module(library((http/http_open))).
:- use_module(library(http/thread_httpd)).
:- use_module(library(http/http_dispatch)).
:- use_module(library(http/http_client)).
:- use_module(library(http/json)).
:- use_module(library(http/http_json)).

:-dynamic(machine/1).
machine_url("https://my-url.com/api/machine").

:- http_handler('/createMachine', add_Machine, []).

server(Port) :-
        http_server(http_dispatch, [port(Port)]).

add_Machine(_Request):- /** Some code **/ .

prolog_init.sh

swipl -s /home/username/prolog.pl -g "server(8000)."

The service file is located at /etc/systemd/system/

prolog.service

[Unit]
Description=Prolog Service

[Service]
Type=simple
ExecStart=/bin/bash /home/username/prolog_init.sh

[Install]
WantedBy=multi-user.target

And these are the commands I execute to set the service up:

sudo systemctl start prolog
sudo systemctl enable prolog

The problem is that when I check the service’s status using sudo systemctl status prolog this is the output I get:

prolog.service - Prolog Service
   Loaded: loaded (/etc/systemd/system/prolog.service; enabled; vendor preset: enabled)
   Active: inactive (dead) since Fri 2019-12-27 23:25:41 UTC; 2 days ago
  Process: 112275 ExecStart=/bin/bash /home/username/prolog_init.sh (code=exited, status=0/SUCCESS)
 Main PID: 112275 (code=exited, status=0/SUCCESS)

Dec 27 23:25:41 LinuxVM systemd[1]: Started Prolog Service.
Dec 27 23:25:41 LinuxVM bash[112275]: % Started server at http://localhost:8000/
Dec 27 23:25:41 LinuxVM bash[112275]: % halt

Am I doing something wrong? Why is my service being halted? Can anyone help me? Thanks!

P.S.: I also posted this question on stack overflow as I didn’t know of this community’s existence. Link: https://stackoverflow.com/questions/59531698/how-can-i-start-my-prolog-web-service-using-a-systemctl-service-on-a-linux-serve

Try using the fully qualified path to swipl in the shell script.

Also try prefixing the command with exec to replace the bash process.

Thanks!
I did as you said (or I hope I did) and this is my new shell script:
exec /usr/bin/swipl -s /home/username/prolog.pl -g "server(8000)"

The problem persists after I reload the service, the server starts but is immediately halted automatically

But it does work when started from a terminal?

I’m not experienced in prolog, but more asking some generic questions and solutions.

Yes, if I start it manually (by typing ./prolog_init.sh) than it works but it was already working manually even before I added the commands you said. I’m struggling to execute it as a service

I once did manage to set it up so that it worked. This was long ago and I honestly do not remember why I did the things I did :frowning: it was a project that I abandoned so I never bothered to document it.

This said, here is what I found:

I have a “server” in a file server.pl. It looks like this:

:- use_module(library(http/thread_httpd)).
:- use_module(library(http/http_dispatch)).
:- use_module(library(http/json)).
:- use_module(library(http/http_json)).
:- use_module(library(http/http_client), [http_read_data/3]).
:- use_module(library(http/http_error)).
:- use_module(library(http/http_header)).

:- http_handler(root(.), not_found, [prefix]).
:- http_handler(root(.), root_get, [method(get)]).
:- http_handler(root(data), data_handler, [methods([get, post])]).
:- http_handler(root(data), resource_handler,
                [prefix, methods([get,delete])]).

not_found(Request) :-
    option(request_uri(U), Request),
    uri_not_found(U, Request).

uri_not_found(U, _Request) :-
    reply_json(_{uri:U}, [status(404)]).
% and so on

then, I have a file in the same directory, run.pl that looks like this (this is the full contents):

:- use_module(library(http/http_unix_daemon)).
:- initialization http_daemon.

:- [server].

Finally, I see here a bash script that looks like it is “installing” the systemd service and (re)starting it. I actually cannot remember what Linux that was, but it was a virtual machine provided to me by our IT services. The script looks like this:

#! /usr/bin/env bash

sudo systemctl stop statsbe.service

BACKEND_DIR=$( pwd )
SWIPL_BIN=$( which swipl )
USER_NAME=$( id -u -n )
KILL_BIN=$( which kill )

cat > statsbe.service <<EOF
[Unit]
Description=The statsbe REST server
After=network.target remote-fs.target nss-lookup.target

[Service]
Type=forking
User=$USER_NAME
WorkingDirectory=$BACKEND_DIR
PIDFile=$BACKEND_DIR/statsbe.pid
ExecStart=$SWIPL_BIN $BACKEND_DIR/run.pl \\
    --pidfile=$BACKEND_DIR/statsbe.pid \\
    --port=5000 \\
    --sighup=quit
ExecStop=$KILL_BIN -HUP \$MAINPID
KillMode=process
KillSignal=SIGHUP
TimeoutStopSec=5
PrivateTmp=true

[Install]
WantedBy=multi-user.target
EOF

sudo cp statsbe.service /etc/systemd/system/statsbe.service
sudo systemctl daemon-reload
sudo systemctl start statsbe.service

I faintly remember that there was an nginx reverse proxy as well but I don’t think this is relevant.

I hope that you find this helpful. I figured this out with some trial and error and reading documentation and now I really hate myself for not writing everything down.

I think the reason for halting is that SWI exists when EOF is received on stdin. You would need some mechanism to keep the process alive.

Hi Hugo,

this might be not that swipl related, but rather linux / systemctl

in order to regist as systemctl service, the exec shell file ( in your case, prolog_init.sh ) might needs to have a #!/usr/bin/bash leading at first line

worth a try :slight_smile:

kind of weird that it terminates right after started, any possibility to get more verbose / debug log ?

Regards

The problem is that the HTTP server runs in a thread and the main thread stops after reading end of file and thus stops the process. One option is to make the toplevel run e.g.,

thread_get_message(Message).

This typically blocks forever, but other threads can make it return by sending a message to the main thread.

Normally I’d advice to use library(http/http_unix_daemon). This provides all the stuff normally associated with managing daemon processes in Unix-like operating systems. Then, the systemd service for e.g. swish is:

# swi-prolog - SWISH server

[Unit]
Description=SWISH

[Service]
UMask=022
Environment=LANG=en_US.utf8
Restart=on-failure
LimitCORE=infinity
StartLimitInterval=60
StartLimitBurst=5
WorkingDirectory=/home/swish/src/swish
ExecReload=/bin/kill -HUP $MAINPID
ExecStart=/home/swish/bin/swipl swish-daemon.pl --no-fork --port=80 --user=www-data --workers=4

[Install]
WantedBy=multi-user.target

Thank you so much! That really helped me get to the solution. I tried with the service you wrote and it worked like a charm, can’t thank you enough. Happy 2020!!