This commit is contained in:
parent
a1880d1516
commit
eb0ca097aa
1 changed files with 78 additions and 19 deletions
97
README.md
97
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))))
|
||||
|
|
Loading…
Reference in a new issue