I got a little burst of inspiration recently and threw some rough experiments together over the course of a few evenings.
Juliana Sims over at the Spritely Institute has been working on porting the Shepherd to Goblins, and I've been excited about that for a while. To quote Juli:
But just changing the internal details of the program isn't particularly interesting, and Goblins promises to let us do magic. So why not do some magic?
The Shepherd port isn't done yet, but I was itching to do a little magic. :)
Shepherd service definitions are just Guile code, and Goblins is written in Guile. So even before the port, can we mash them up a little bit?
A simple Shepherd service looks like this:
(define mcron
(service
'(mcron)
;; Run /usr/bin/mcron without any command-line arguments.
#:start (make-forkexec-constructor '("/usr/bin/mcron"))
#:stop (make-kill-destructor)
#:respawn? #t))
The start
and stop
actions are Guile procedures, in this case procedures that spawn a new process and kill the process. Shepherd saves the return value from the start
procedure and implicitly passes it to the stop
procedure. But this is pretty flexible! Could we do something other than spawning and killing new processes in this service constructor?
Well yes, we can:
(define (^hello bcom)
(display "Spawning goblins service...\n")
(lambda ()
"Hello world!"))
(define hello-service
(service
'(hello)
#:start (make-goblins-constructor ^hello)
#:stop (make-goblins-destructor)
#:actions (make-goblins-actions)))
This is something a little different now! Instead of calling make-forkexec-constructor
when the service starts, we call make-goblins-constructor
- which spawns a new Goblins vat and spawns our new object in that vat. The underlying code for this can be found here.
And we'll want to make this new Goblins service accessible somehow, right? One noteworthy thing about object capability programming is that you need a reference to an object to interact with it. So to bootstrap that, the make-goblins-actions
procedure registers a custom action for this service which lets you retrieve a sturdyref to the new object:
$ herd start hello
Spawning goblins service...
Service hello has been started.
$ herd get-sturdyref hello
ocapn://57f2421cf4ae620aa78e1a35b6675fa07995cae6d4e185429d0119e2a416899b.tcp-tls/s/S4vB1fLu3T4MD76ELh52Wi3pQ3rasc6HXBf9pxPbo3A?host=localhost&port=58265
It's using a TCP/TLS netlayer because there's no Unix socket netlayer available for use yet. Once that's ready, I'd want to switch this over to use that instead. No need to expose these objects on the network, after all - even on localhost. (If you wanted to expose a Goblins object on the network, that could be another Shepherd service.)
Is this the right design for Goblins user/system services? I don't know! But I think it's an interesting experiment. :)