The example uses pengin_spawn/2, pengine_ask/2, pengine_next/1 and receive/1. Where and how is a pengine/webprolog deallocated? What would happen if I do, i.e. ask main/1 with a closed and shorter list. Would main/1 be steadfast and deallocate a pengine/webprolog at the same time?
Welcome to SWI Web Prolog!
Are there some setup_call_cleanup/3 patterns possible/impossible or necessary/unnecessary for pengines/webprolog? setup_call_cleanup/3 has been introduced in many Prolog systems, since it helps accessing or modifying resources.
The typical pattern to access a resource such as a server, is the following programming pattern, which has the advantage that it can be used via backtracking and also works nicely with surrounding cut:
The chapters 4) and 5) are extracted from the next draft of “Web Prolog and the programmable Prolog Web” that I’m working on. This draft is too messy to distribute at this point in time, but will be announced when I think it’s ready for public consumption.
So equipped with this, let's move on to your other questions:
No, it has nothing to do with links. Unfortunately, I noticed that documentation for flush/0 is missing from the manual. But it’s very simple. Here’s a quote from the intro paper:
Calling the utility predicate flush/0 - also borrowed from Erlang - allowed us to inspect the content of the top-level mailbox.
It means that the shell (or rather the pengine to which the shell is attached) received a message informing you that the pengine which was spawned no longer exists. Erlang has such messages too.
This works, for both ?-main(List) and ?-main([A,B]), just as before. However, I don’t think the use of setup_call_cleanup/3 makes any sense here, since pengine_exit/2 will always run, but won’t do anything at all since the pid at this point in time points to a pengine which is already gone.
The calls in the second and third argument to setup_call_cleanup/3 are deterministic and they don’t fail or throw exceptions, not even if the spawned pengine for some reason is already dead or if its creation didn’t succeed in the first place. There is a pid, but it doesn’t point to an active pengine. This too is Erlang-ish behaviour.
The only thing that might happen is if the call to collect_in_list/2 hangs, i.e. if no success messages show up. There can be a network problem, for example.
So what can be done about that? Here’s one way to handle the situation, assuming we want ?-main(List) to always terminate, and the spawned pengine to die:
Sure, my first (crappy) implementation used posix threads (thread_create/3 and friends) only (just like library(pengines)), the current PoC uses Paul Tarau’s engines and fewer threads. An implementation in Erlang might use Erlang processes. An implementation in Java might use something else. What? Well, I leave that to you to propose. The point is that there are many way to implement Web Prolog, and I’m not yet sure which way is the best. I’m still in the specification phase, and would prefer to remain there for a while.
I’m not sure where you think setup_call_cleanup/3 would help. Can you elaborate?
exit(true) tells the pengine to die after having run the query to completion, wheras exit(false) means you can keep using it for more querying.
That could and probably should be added, but I still don’t understand how setup_call_cleanup/3 would help, so I would use pengine_exit/2 in combination with a timeout as in the previous example.
If you know the first solution is all you want, I would propose to use once(q(X)) as a goal.
But hey, I’m aware of the problem, and I’m not sure a 100% satisfying solutions exists for immediately killing (remote) pengines when they are no longer needed. I have a few ideas, and one of the best might be the following. A Web Prolog node can (and should) be equipped with a stateless (think RESTful) HTTP API as well as a WebSocket API. rpc/2-3, as implemented above, has to use the WebSocket API, but rpc/2-3 can also be implemented using HTTP as transport (one might use an option transport to choose between the two implementations). Here’s a somewhat ugly implementation:
To understand how the stateless HTTP is supposed to work, you should first look at section 4.9 in the paper, and if you want to know (much!) more, at section 6.3 - 6.5 in the longer manuscript. The tutorial in the PoC provides a couple of examples.
Jan B, I thought I knew enough about setup_call_cleanup/2 to use it once in a while when it’s appropriate (when opening files, for example), but who knows, I may be missing something. I’m sure it would deserve a place in Web Prolog, but I still don’t get what kind of role it can play in solving the problems we’ve discussed above. I understand that call_with_time_limit/2 might be useful (instead of the solution based on receive/1-2 and timeouts), but you keep talking about setup_call_cleanup/2 all the time, and that makes me confused. I’m happy to make another attempt to understand.
Paulo, API looks great!. So it does indeed seem like Logtalk might be a suitable implementation language for a Web Prolog node. And yes, game-based demos are effective, so I’d love to find out if the tbbt example can be rewritten in Web Prolog.
(Now off to say hej to our new Swedish friend Håkan before going to bed…)
(Strange, BTW, I just noticed that there’s a limit on how many answers one may write to the same post in a row. Didn’t know that until know, and that’s why you get my responses to you both in the same post.)