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
|
# 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))))
|
||||||
|
|
Loading…
Reference in a new issue