2017-08-10 19:17:28 +00:00
|
|
|
#lang syndicate
|
2016-11-28 23:28:08 +00:00
|
|
|
;; Extremely simple single-actor supervision
|
|
|
|
;; Vastly simplified compared to the available options in OTP
|
|
|
|
|
2016-12-06 20:47:39 +00:00
|
|
|
(provide supervise
|
2017-02-20 17:54:52 +00:00
|
|
|
supervise/spawn)
|
2016-11-28 23:28:08 +00:00
|
|
|
|
|
|
|
(require racket/exn)
|
|
|
|
(require "core.rkt")
|
|
|
|
(require "dataflow.rkt")
|
|
|
|
(require "hierarchy.rkt")
|
|
|
|
(require "store.rkt")
|
|
|
|
|
|
|
|
(require (submod "actor.rkt" implementation-details))
|
2016-11-29 01:47:22 +00:00
|
|
|
(require (for-syntax syntax/parse))
|
2016-11-28 23:28:08 +00:00
|
|
|
|
|
|
|
(require/activate "drivers/timestate.rkt")
|
|
|
|
|
2016-11-29 01:47:22 +00:00
|
|
|
(define-syntax (supervise stx)
|
|
|
|
(syntax-parse stx
|
|
|
|
[(_ name:actor-name expr ...)
|
|
|
|
(syntax/loc stx
|
2016-12-06 20:47:39 +00:00
|
|
|
(supervise* (lambda () name.N)
|
|
|
|
void
|
|
|
|
(lambda () expr ...)))]))
|
2016-11-29 01:47:22 +00:00
|
|
|
|
2017-02-20 17:54:52 +00:00
|
|
|
(define-syntax (supervise/spawn stx)
|
2016-12-06 20:47:39 +00:00
|
|
|
(syntax-parse stx
|
|
|
|
[(_ (~or (~optional (~seq #:name name-expr) #:defaults ([name-expr #'#f])
|
|
|
|
#:name "#:name")
|
|
|
|
(~optional (~seq #:linkage [linkage-expr ...]) #:defaults ([(linkage-expr 1) '()])
|
|
|
|
#:name "#:linkage"))
|
|
|
|
...
|
|
|
|
O ...)
|
|
|
|
(syntax/loc stx
|
|
|
|
(supervise* (lambda () name-expr)
|
|
|
|
(lambda () linkage-expr ... (void))
|
2017-02-15 23:18:19 +00:00
|
|
|
(lambda () (spawn O ...))))]))
|
2016-12-06 20:47:39 +00:00
|
|
|
|
|
|
|
(define (supervise* supervisor-name-thunk linkage-thunk actor-producing-thunk)
|
2016-11-29 01:47:22 +00:00
|
|
|
;; Awkward: the name applies to any and all potential supervisors
|
|
|
|
;; produced by actor spawns in actor-producing-thunk.
|
|
|
|
(with-store [(current-action-transformer
|
2016-12-06 20:47:39 +00:00
|
|
|
(supervise-spawn supervisor-name-thunk linkage-thunk (current-action-transformer)))]
|
2016-11-28 23:28:08 +00:00
|
|
|
(actor-producing-thunk)))
|
|
|
|
|
2016-12-06 20:47:39 +00:00
|
|
|
(define ((supervise-spawn supervisor-name-thunk linkage-thunk previous-action-transformer) ac)
|
2016-11-28 23:28:08 +00:00
|
|
|
(match (previous-action-transformer ac)
|
2017-02-15 23:18:19 +00:00
|
|
|
[(? actor? s) (supervise** (or (supervisor-name-thunk) (gensym 'supervisor)) linkage-thunk s)]
|
2016-11-28 23:28:08 +00:00
|
|
|
[other other]))
|
|
|
|
|
2016-12-06 20:47:39 +00:00
|
|
|
(define (supervise** supervisor-name linkage-thunk supervisee-spawn-action)
|
2016-11-29 01:47:22 +00:00
|
|
|
(actor-action #:name supervisor-name
|
|
|
|
(react
|
2017-02-15 23:18:19 +00:00
|
|
|
(linkage-thunk) ;; may contain e.g. linkage instructions from during/spawn
|
2016-11-29 01:47:22 +00:00
|
|
|
|
2017-07-05 11:13:36 +00:00
|
|
|
(define root-supervisor-facet (current-facet-id))
|
2016-11-29 01:47:22 +00:00
|
|
|
|
|
|
|
(field [supervisee-name 'unknown])
|
|
|
|
|
|
|
|
(define intensity 1)
|
|
|
|
(define period 5000) ;; milliseconds
|
|
|
|
(define sleep-time 10) ;; seconds
|
|
|
|
(field [restarts '()])
|
|
|
|
|
|
|
|
(define (add-restart!)
|
|
|
|
(define now (current-inexact-milliseconds))
|
|
|
|
(define oldest-to-keep (- now period))
|
|
|
|
(restarts (filter (lambda (r) (>= r oldest-to-keep))
|
|
|
|
(cons (current-inexact-milliseconds) (restarts))))
|
|
|
|
(when (> (length (restarts)) intensity)
|
|
|
|
(log-error "Supervised process ~s/~s ~a reached max restart intensity. Sleeping for ~a seconds"
|
|
|
|
supervisor-name
|
|
|
|
(supervisee-name)
|
|
|
|
(current-actor-path)
|
|
|
|
sleep-time)
|
|
|
|
(sleep sleep-time)))
|
|
|
|
|
|
|
|
(field [should-run? #f]
|
|
|
|
[ok? #f])
|
|
|
|
|
|
|
|
(on (rising-edge (not (ok?)))
|
|
|
|
(should-run? #f)
|
|
|
|
(ok? #t)
|
|
|
|
(retract! ?)
|
|
|
|
(flush!)
|
|
|
|
(should-run? #t))
|
|
|
|
|
|
|
|
(define (catch-exns thunk k)
|
|
|
|
(with-handlers ([(lambda (e) #t)
|
|
|
|
(lambda (e)
|
|
|
|
(log-error "Supervised process ~s/~s ~a died with exception:\n~a"
|
|
|
|
supervisor-name
|
|
|
|
(supervisee-name)
|
|
|
|
(current-actor-path)
|
|
|
|
(if (exn? e)
|
|
|
|
(exn->string e)
|
|
|
|
(format "~v" e)))
|
|
|
|
(add-restart!)
|
|
|
|
(ok? #f))])
|
|
|
|
(call-with-values thunk k)))
|
|
|
|
|
|
|
|
(on (rising-edge (should-run?))
|
|
|
|
(react (stop-when (rising-edge (not (should-run?))))
|
|
|
|
(field [proc #f])
|
|
|
|
|
|
|
|
(define (handle-transition! txn)
|
|
|
|
(match txn
|
|
|
|
[#f
|
|
|
|
;; N.B. TODO: Polling (event of #f) will never
|
|
|
|
;; reach the inner actor, since actor-behavior
|
|
|
|
;; doesn't bother executing anything if it is
|
|
|
|
;; given #f.
|
|
|
|
(void)]
|
|
|
|
[(<quit> _ acs)
|
|
|
|
(perform-actions! acs)
|
|
|
|
;; N.B. TODO: what to do with the exception
|
|
|
|
;; carried in the quit struct?
|
2017-07-05 11:13:36 +00:00
|
|
|
(stop-facet root-supervisor-facet)]
|
2016-11-29 01:47:22 +00:00
|
|
|
[(transition st acs)
|
|
|
|
(perform-actions! acs)
|
|
|
|
(proc (update-process-state (proc) st))]))
|
|
|
|
|
|
|
|
(on-start
|
|
|
|
(catch-exns
|
|
|
|
(lambda ()
|
2017-08-05 23:36:15 +00:00
|
|
|
(define-values (initial-proc initial-transition initial-assertions)
|
|
|
|
(actor->process+transition/assertions supervisee-spawn-action))
|
2016-11-29 01:47:22 +00:00
|
|
|
(proc initial-proc)
|
|
|
|
(supervisee-name (process-name initial-proc))
|
2017-08-05 23:36:15 +00:00
|
|
|
(patch! (patch initial-assertions trie-empty))
|
2016-11-29 01:47:22 +00:00
|
|
|
initial-transition)
|
|
|
|
handle-transition!))
|
|
|
|
|
|
|
|
(on-event
|
|
|
|
[e (when (proc)
|
|
|
|
(catch-exns
|
|
|
|
(lambda () ((process-behavior (proc)) e (process-state (proc))))
|
|
|
|
handle-transition!))]))))))
|