From eb0ca097aa0ab568c9e47f8446fd77494fd1b03c Mon Sep 17 00:00:00 2001 From: Reid D McKenzie Date: Sun, 24 May 2020 01:22:43 -0600 Subject: [PATCH] --- README.md | 97 ++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 78 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index b1a7ed4..a1ee8ea 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ # Flowmetal -> That of which servitors are made +> A shining mercurial metal laden with sensors and almost infinitely reconfigurable. +> +> The stuff of which robots and servitors are made. Flowmetal is a substrate for automation. It attempts to provide a programming environment wherein programs are durable, evented and asynchronous aimed at what would traditionally be described as scripting or coordination. @@ -68,19 +70,64 @@ In this setup, the Flowmetal interpreters are able to interact with an external For instance this program would use the external connector stubs to build up interaction(s) with an external system. ```lisp +(defpackage flowmetal.time + (defenum time-unit + "Calendar-independent durations." + +milliseconds+ + +seconds+ + +hours+ + +days+) + + (defrecord duration [num : int?, scale : time-unit?] + "A type for representing scalar durations.") + + (defn as-milliseconds [d : duration?] + : duration? + "Normalize a duration to a number of milliseconds." + (match d + [(duration x +days+) (duration (* x 24) +hours+)] + [(duration x +hours+) (duration (* x 60) +minutes+)] + [(duration x +minutes+) (duration (* x 60) +seconds+)] + [(duration x +seconds+) (duration (* x 1000) +milliseconds+)] + [(duration x +milliseconds+) d])) + + ;; A type of one value used to represent an error + (defenum timeout + +timeout+) + + (defendpoint with-timeout! + [d : duration? + f : (fn? [] : a)] + : a + + ) + +) (defpackage com.twitter.wilson (require ;; The log lets you record status information into a program's trace - [flowmetal.log :refer [log]] + [flowmetal.log + :refer [log!]] ;; The time system lets you put bounds on the implicit awaiting Flowmetal does - [flowmetal.time :refer [with-timeout, timeout?, duration, duration?, sleep]] + [flowmetal.time + :refer [with-timeout!, timeout?, make-duration, duration?, +seconds+, +hours+, sleep!]] ;; JSON. Simple enough - [flowmetal.json :refer [loads, dumps, json?]] + [flowmetal.json + :refer [loads, dumps, json?]] ;; Extensions! Provided by other systems. - ;; These two allow for HTTP requests to be made and callbacks to be received. - [http.callback :refer [make-callback, get-callback, callback?]] - [http.request :refer [post, error?, dns-error?, connection-error?, response-error?]]) + ;; + ;; This one allows for an external service to receive HTTP callbacks on Flowmetal's behalf. + [http.callback + :refer [make-callback!, get-callback!, callback?]] + ;; This one allows for an external service to make HTTP requests on Flowmetal's behalf. + [http.request + :refer [post!, error?, dns-error?, connection-error?, response-error?]]) + + (defenum stage + +reboot+ + +bios-update+ + +reinstall+) ;; FIXME: how to do table optimization? (defn fib [x] @@ -89,11 +136,18 @@ For instance this program would use the external connector stubs to build up int [1 1] [_ (+ (fib (- x 1) (- x 2)))])) - (defn retry-http [f :- (fn [] :- a) - backoff-fn :- (fn [int?] :- duration?) :default (fn [x] (duration (fib x) :seconds)) - backoff-count :- int? :default 0] - :- a - """The implementation of HTTP retrying.""" + (defn retry-http [f + : (fn? [] a?) + backoff-fn + : (fn? [int?] duration?) + :default (fn [x : int?] + : duration? + (make-duration (fib x) +seconds+)) + backoff-count + : int? + :default 0] + : a + """The implementation of HTTP with retrying.""" (let [response (f)] (if (not (error? response)) response @@ -104,16 +158,20 @@ For instance this program would use the external connector stubs to build up int (do (sleep (backoff-fn backoff-count)) (retry-http* f backoff-fn (+ backoff-count 1))))))) - (defn job [hostname :- str, - stages :- (list? str?), - job-timeout :- duration? :default (duration 3 :hours)] - :- (union timeout? json?) + (defn job [hostname + : str? + stages + : (list? stage?) + job-timeout + : duration? + :default (duration 3 :hours)] + : (union? [timeout? json?]) """Run a wilson job, wait for the callback and process the result. By default the job is only waited for three hours. """ - (let [callback :- callback? (make-callback) + (let [callback : callback? (make-callback!) job (retry-http (fn [] (post "http://wilson.local.twitter.com" @@ -123,8 +181,9 @@ For instance this program would use the external connector stubs to build up int :stages [stages] :callbacks [{:type :http, :url callback}]}))))] - (let [result (with-timeout (duration 3 :hours) - (get-callback callback))] + (let [result (with-timeout! (duration 3 :hours) + (fn [] + (get-callback callback)))] (if-not (timeout? result) (loads result) result))))