Prolog 101: how to make my application "recognize" the changes in .pl files?

Sorry for the very basic question but I’m quite desperate. Until yesterday I didn’t even know what Prolog was, and now I’m managing a Prolog application written by someone else on a server I’ve never interacted with. I’m trying to read docs here and there but I need quick basic help. Thank you if you can.

So I have a number of prolog files in the server home/user folder:
ptrolog

and I did a number of edits to them. I thought Prolog was interpreted and so I thought the edits would immediately appear in the application but I discovered it’s compiled and so I tried to compile the changes but I’m so lost.
I went to the folder where the files are and I typed swipl and then I used make. and I got this:

?- make.
% Updating index for library /usr/lib/swi-prolog/xpce/prolog/lib
true.

but nothing changed in the application. Do I need to do anything else? Different? Sorry again for the very basic question, I’m committed to improve but I really have little time to perform the first update and I’m lost. Thank you.

Probably the question is how the app was started. If it’s already running and you want to get it to pick up the changes, you’d have to connect to the running application to run make (the make you ran there was just in a new swipl session that hadn’t loaded any files). Alternatively, if you reload the app, it would probably pick up the changes…but again, that depends on how the project is running. If it’s running off a saved state (what I assume you mean by “compiled”), you’ll need to load the files (something like swipl -l *.pl or swipl followed by [base, base_ext, ...]) and then run save_program or similiar.

As I say though, it really depends on how exactly your app is running…when I’ve run prolog servers in production, I’d do so by running something like swipl -o $OUTPUT_FILE --foreign=save --autoload=true --stand_alone=true --goal=$MAIN_GOAL --toplevel=halt -O -c $ENTRY_POINT_FILE and then uploading the generated $OUTPUT_FILE to the server (where $MAIN_GOAL is the goal/“function” that starts things off and $ENTRY_POINT_FILE is the file that loads everything else. However, it could certainly also be run interactively or in any number of other ways…

1 Like

My god thank you so much for your reply but I understood little of it. :sweat_smile: The “app” is a windows Unity executable that, when started, connects to the prolog server to load some data from there.

I don’t really know how (maybe because I used consult().) but now when I use make. I get:

$ /path/to/files/modified_file compiled into modified_file 0.11 sec, X clauses
true

where X is the number of rows of code I edit.
So, the code gets compiled, it seems. But when I start the app, my edit are ignored. So I obviously miss something.

Can you determine how that server is being started?

1 Like

There’s a file left by the previous dev that says:

When server starts: `user@server:~/path/to/files$ screen ./Autostart.sh`
to detach a screen session: "Ctrl-a d"

Content of Autostart.sh is:

#!/bin/bash
#
swipl loadAll.pl

Is this useful somehow?

Aha, indeed! So you probably want to stop that server and then re-run the command (presumably by ssh user@server, then screen to connect to the screen session running the app, stop it via control-c, then run Autostart.sh again, and disconnect via Ctrl-a d) .

It is also possible to set up a remote toplevel on the server (see prolog_server/2) which would then able you to remotely connect to the running swipl with telnet and just run make there to update the changed files.

1 Like

Thank you so much for your support! I’ll try to do that but does this mean that I have to stop and restart the server every time I do some changes to the code?

Depending on how the server is running, you could probably also just run make. or load files as appropriate from the swipl session running in screen (assuming it has the toplevel running & the server process isn’t blocking on the main thread)

1 Like

If security is bothering, the "libssh" pack for SWI-Prolog can also come handy. It provides a pretty complete toplevel including command line editing, color output, etc. Allows multiple people to play around of the same Prolog instance :slight_smile:

library(http/http_unix_daemon) is a good way to start HTTP servers on Unix-like platform. By default this captures SIGHUP to call make/0. You can also add some request to your server to run make/0 (typically authenticated, altough just being able to run make/0 is not that security sensitive as long as the files are safe).

The trick used by library(http/http_unix_daemon) is to block the main thread in thread_get_message/1 and setup signal handlers using on_signal/3 that use thread_send_message(main, Message) to inform the main thread to undertake some action.

Finally, on linux, you could use "inotify" pack for SWI-Prolog to make Prolog watch for changing files and reload them automatically :slight_smile:

Note that reloading source files asynchronously is safe in SWI-Prolog, provided you do not change the signature of any of the predicates. See SWI-Prolog -- Reloading files, active code and threads

2 Likes

Thank you again for all the feedbacks, you are all very kind.

Allow me to re-ask a very basic question tho because I still don’t understand one basic thing, way more basic than all your very deep suggestions: Why do I have to restart the server after I get this

$ /path/to/files/modified_file compiled into modified_file 0.11 sec, N clauses
true

and does this mean I have to restart the server every time I implement the slightest change to the code? And, if I don’t have to restart the server everytime, why do I have to do it now? Can you understand my doubt?

I am very unconfortable “playing” with the running server unless I’m 200% sure, since it’s a production one. If I shut it down and somehow don’t manage to load it up, a lot of people all around Europe will not be able to use the application anymore.

You should be ok after the reload. If not, I guess some cache is bothering you. Are you caching stuff internally? Maybe you are using tabling? In the latter case an abolish_all_tables/0 should help. If you cache something in dynamic predicates you need to update the caches. Note that make/0 can be hooked (see the source) to deal with derived data that requires updating.

1 Like

Prolog aside, in general I would run a local version of the server to develop against, get everything working interactively (either using make to pull in the changes or using the integration with my editor to load in files on change), restarting as needed without worrying about it, then when it’s all working, deploy the new code & restart the production server.

1 Like

Just to be clear, I think you are absolutely right and this is how the previous dev did and I’m sure this is how the next dev will do.

My temporary job here was just to update the app once, and since I am 300% my code is correct, I was no afraid to “update the code in production”. It’s generally wrong yeah but it’s an emergency and I’m really really really sure the code won’t broke anything. I extremely like to study a new language.

But then the whole “restart the server” thing came out, with the attach/detach the session thing, remote toplevels, security packs, tabling, et cetera. All of this I have to investigate and study because I have no idea what all of this is.

And for this I’m afraid doing anything with the server. I just hoped to edit some code and run it.

Sorry for the vent. These are not being great days. You are absolutely friendly and considerate.

1 Like

Sorry guys but how do I stop/start a Swipl server by command line? I’m finding informations about using halt. but that’s for exiting swipl. Do I have to use http_stop_server? I am terrified by the possibility of me destroying the server and being unable to start it again. Can you please help me understand? Sorry and thank you :pensive:

Tara,

Your situation sounds pretty crazy.

I would never be able to have such confidence, surely not in a language environment and production setup i know nothing about.

And doing a hot (or cold) reload on a product server with customers depending on it all over Europe made me think about those movies where the hero has 5 seconds to cut either the red or the blue wire to an attached device (production server?).

I think this is a commercial decision not only a technical one and should be done with full management knowledge and support.

Also, management should – ideally – support creating a replicated environment to test any intervention you might want to do.

Dan

1 Like

I don’t disagree with you, that’s why I’m still here thinking what to do. I said I’m 300% sure of my code because it was a very very very minor tweak. But I’m having such a hard time understanding if there’s a simple command to restart the prolog server or if I have to do something more complex that I didn’t understand.

You may not know what the reload routine does and whether there exist more than one with all kind of implicit condition checks, each doing something else, and-- what if you catch the “wrong” reload routine that initializes all data – somehow …

I think you may want to advocate for the customers to let you set up a parallel setup to try things out first the savings of not doing this may be significantly overridden by the cost of doing the wrong thing

1 Like

Previous dev set up a file Autostart.sh that is

swipl loadAll.pl

loadAll.pl is like this:

:- module('App_Name', [version/2]).
:- ['file.pl, anotherFile.pl. thirdFile.pl].
version('0.65', 'Mar 11, 2021').
:- server(8000).

Isn’t this the “load routine”?

I think you may want to advocate for the customers to let you set up a parallel setup to try things out first the savings of not doing this may be significantly overridden by the cost of doing the wrong thing

I don’t know what to say other than you’re absolutely right. But this won’t happen. I was tasked to just apply a tiny update to the code, then the whole thing will be passed to another dev. I had no idea it was this difficult, I thought it was just edit file > compile > that’s all folks. Sorry.

the load routine is what the prolog code actually does …

Was this designed to work as a hot-reload – are there any environment variables that are expected to be set, any files that have certain preexisting contents assumed to exist that is read, any networked calls that are checked against, etc. etc.

Edit:

All i am saying is that you have no 100% certainty what swpil loadAll.pl actually will do – and hence there is a commercial risk here that – I, personally, would never want to take on in a production environment – before significant testing in a parallel environment.

1 Like

I steadfastly thank you for your support and patience. I still have no idea what to do here (I have to restart the server because I edited a file but restarting the server is so risky and difficult) so only thing I can do is pack my things and refuse the task I’ve been given. Thank you again, may all be in your favour.