Here's an example of a barebones gall agent that just starts a thread:
thread-starter.hoon
/+ default-agent, dbug=* card card:agent:gall%- agent:dbug^- agent:gall|_ =bowl:gall+* this .def ~(. (default-agent this %|) bowl)::++ on-init on-init:def++ on-save on-save:def++ on-load on-load:def++ on-poke|= [=mark =vase]^- (quip card _this)?+ mark (on-poke:def mark vase)%noun?+ q.vase (on-poke:def mark vase)(pair term term)=/ tid `@ta`(cat 3 'thread_' (scot %uv (sham eny.bowl)))=/ ta-now `@ta`(scot %da now.bowl)=/ start-args [~ `tid byk.bowl(r da+now.bowl) p.q.vase !>(q.q.vase)]:_ this:~[%pass /thread/[ta-now] %agent [our.bowl %spider] %poke %spider-start !>(start-args)]======++ on-watch on-watch:def++ on-leave on-leave:def++ on-peek on-peek:def++ on-agent|= [=wire =sign:agent:gall]^- (quip card _this)?+ -.wire (on-agent:def wire sign)%thread?+ -.sign (on-agent:def wire sign)%poke-ack?~ p.sign%- (slog leaf+"Thread started successfully" ~)`this%- (slog leaf+"Thread failed to start" u.p.sign)`this====++ on-arvo on-arvo:def++ on-fail on-fail:def--
And here's a minimal thread to test it with:
test-thread.hoon
/- spider=, strand=strand:spider^- thread:spider|= arg=vase=/ m (strand ,vase)^- form:m|= strand-input:strand?+ q.arg [~ %fail %not-foo ~]%foo[~ %done arg]==
Save them as /app/thread-starter.hoon
and /ted/test-thread.hoon
respectively in the %base
desk, |commit %base
, and start the app with |rein %base [& %thread-starter]
.
Now you can poke it with a pair of thread name and argument like:
:thread-starter [%test-thread %foo]
You should see Thread started successfully
.
Now try poking it with [%fake-thread %foo]
, you should see something like:
Thread failed to start/app/spider/hoon:<[355 5].[355 60]>[%no-file-for-thread %fake-thread]/app/spider/hoon:<[354 5].[355 60]>/app/spider/hoon:<[353 3].[359 19]>/app/spider/hoon:<[350 3].[359 19]>/app/spider/hoon:<[346 3].[359 19]>/app/spider/hoon:<[343 3].[359 19]>/app/spider/hoon:<[341 3].[359 19]>/app/spider/hoon:<[340 3].[359 19]>/app/spider/hoon:<[336 3].[359 19]>/app/spider/hoon:<[335 3].[359 19]>/app/spider/hoon:<[202 24].[202 68]>/app/spider/hoon:<[200 7].[207 9]>/app/spider/hoon:<[199 5].[208 17]>/app/spider/hoon:<[197 5].[208 17]>/app/spider/hoon:<[196 5].[208 17]>/sys/vane/gall/hoon:<[1.370 9].[1.370 37]>
Analysis
We can ignore the input logic, here's the important part:
=/ tid `@ta`(cat 3 'thread_' (scot %uv (sham eny.bowl)))=/ ta-now `@ta`(scot %da now.bowl)=/ start-args [~ `tid byk.bowl(r da+now.bowl) p.q.vase !>(q.q.vase)]:_ this:~[%pass /thread/[ta-now] %agent [our.bowl %spider] %poke %spider-start !>(start-args)]==
You can generate a tid any way you like, just make sure it's unique. Here we just use the hash of some entropy prefixed with thread_
.
Then it's just a poke to %spider
with the mark %spider-start
and a vase containing start-args. Spider will then respond with a %poke-ack
with a (unit tang)
which will be ~
if it started successfully or else contain an error and a traceback if it failed. Here we test for this and print the result:
++ on-agent|= [=wire =sign:agent:gall]^- (quip card _this)?+ -.wire (on-agent:def wire sign)%thread?+ -.sign (on-agent:def wire sign)%poke-ack?~ p.sign%- (slog leaf+"Thread started successfully" ~)`this%- (slog leaf+"Thread failed to start" u.p.sign)`this====