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

1 Like

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.

1 Like

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.

1 Like

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

1 Like

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
3 Likes

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!!