This commit is contained in:
Reid D McKenzie 2020-05-24 01:22:43 -06:00 committed by GitHub
parent a1880d1516
commit eb0ca097aa

View file

@ -1,6 +1,8 @@
# Flowmetal # 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. 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. 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. For instance this program would use the external connector stubs to build up interaction(s) with an external system.
```lisp ```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 (defpackage com.twitter.wilson
(require (require
;; The log lets you record status information into a program's trace ;; 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 ;; 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 ;; JSON. Simple enough
[flowmetal.json :refer [loads, dumps, json?]] [flowmetal.json
:refer [loads, dumps, json?]]
;; Extensions! Provided by other systems. ;; 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?]] ;; This one allows for an external service to receive HTTP callbacks on Flowmetal's behalf.
[http.request :refer [post, error?, dns-error?, connection-error?, response-error?]]) [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? ;; FIXME: how to do table optimization?
(defn fib [x] (defn fib [x]
@ -89,11 +136,18 @@ For instance this program would use the external connector stubs to build up int
[1 1] [1 1]
[_ (+ (fib (- x 1) (- x 2)))])) [_ (+ (fib (- x 1) (- x 2)))]))
(defn retry-http [f :- (fn [] :- a) (defn retry-http [f
backoff-fn :- (fn [int?] :- duration?) :default (fn [x] (duration (fib x) :seconds)) : (fn? [] a?)
backoff-count :- int? :default 0] backoff-fn
:- a : (fn? [int?] duration?)
"""The implementation of HTTP retrying.""" :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)] (let [response (f)]
(if (not (error? response)) (if (not (error? response))
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)) (do (sleep (backoff-fn backoff-count))
(retry-http* f backoff-fn (+ backoff-count 1))))))) (retry-http* f backoff-fn (+ backoff-count 1)))))))
(defn job [hostname :- str, (defn job [hostname
stages :- (list? str?), : str?
job-timeout :- duration? :default (duration 3 :hours)] stages
:- (union timeout? json?) : (list? stage?)
job-timeout
: duration?
:default (duration 3 :hours)]
: (union? [timeout? json?])
"""Run a wilson job, wait for the callback and process the result. """Run a wilson job, wait for the callback and process the result.
By default the job is only waited for three hours. By default the job is only waited for three hours.
""" """
(let [callback :- callback? (make-callback) (let [callback : callback? (make-callback!)
job (retry-http job (retry-http
(fn [] (fn []
(post "http://wilson.local.twitter.com" (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] :stages [stages]
:callbacks [{:type :http, :url callback}]}))))] :callbacks [{:type :http, :url callback}]}))))]
(let [result (with-timeout (duration 3 :hours) (let [result (with-timeout! (duration 3 :hours)
(get-callback callback))] (fn []
(get-callback callback)))]
(if-not (timeout? result) (if-not (timeout? result)
(loads result) (loads result)
result)))) result))))