malkomalko
1/17/2013 - 12:33 AM

README.md

#lang racket/base

(provide foo)

(define (foo) "foo")

(printf "test-mod: ~v\n" (foo))
#lang racket/base

(define (load-and-foo)
  (define sub-custodian (make-custodian))
  (printf "Starting worker...\n")
  (parameterize ((current-custodian sub-custodian))
    (thread (lambda ()
        (parameterize ((current-namespace (make-base-namespace)))
		(dynamic-require "other-mod.rkt" #f)))))
  (sleep 3.5)
  (printf "Terminating worker...\n")
  (custodian-shutdown-all sub-custodian))

(provide load-and-foo)
#lang racket/base

(require "test-mod.rkt")

(let loop ()
  (printf "other-mod: ~v\n" (foo))
  (sleep 1)
  (loop))

Demonstrates the use of Racket's custodians and namespaces to create enough isolation to "reboot" programs without restarting the whole of Racket, including possibly recompiling and reloading code.

To experiment with this:

$ racket ~/src/racket-experiments$ racket
Welcome to Racket v5.3.1.4.
-> (require "reloader.rkt")
-> (load-and-foo)
Starting worker...
test-mod: "foo"
other-mod: "foo"
other-mod: "foo"
other-mod: "foo"
other-mod: "foo"
Terminating worker...
-> 

Subsequent runs of (load-and-foo) will reload the code from scratch. If you've edited one of test-mod.rkt or other-mod.rkt in the meantime, the changes will show up.

Note that other-mod.rkt runs a loop "forever", but that reloader.rkt terminates all threads in the nested custodian.