You can create the thread under a different custodian, where the custodian itself is created outside of the request-handling thread (eg. the top level of a module).
It doesn’t look like threads created in a handler inherit the request-handling thread’s custodian, though, so you might be running into some other issue. This code behaves as expected:
#lang racket/base
(require web-server/http
web-server/servlet-dispatch
web-server/web-server)
(serve
#:port 9999
#:dispatch (dispatch/servlet
(lambda (_req)
(thread
(lambda ()
(let loop ()
(displayln "hello from thread")
(sleep 1)
(loop))))
(response/xexpr '(h1 "Hello")))))
i.e. it prints the message even after the request completes.
That’s interesting. I had created a thread for sending a notification email, and the email wasn’t sent until I added a (sleep 3)
in the main request thread, so I assumed the issue was the premature termination of my notification thread.
@popa.bogdanp how do you create a thread with a custodian other than the current custodian?
Here’s my main function for context: (define (axio-app-init environment route get-user)
(let* ([ instance-id (string->number (vector-ref (current-command-line-arguments) 0)) ]
[ env (get-app-env environment) ]
[ port (+ (app-env-port-base env) instance-id) ]
[ axio-context (axio-init environment) ])
(void
(serve
#:dispatch (seq:make (log:make #:format log:extended-format
#:log-path (format "~a.log" (symbol->string environment)))
(lift:make (λ (request)
(front-controller axio-context request route get-user))))
#:port port))
(do-not-return)))
You can create a new custodian at the top level, then parameterize current-custodian
around the extent of thread
. Something like:
(define task-custodian (make-custodian))
(define (axio-app-init ...) ...)
(define (front-controller ...)
(parameterize ([current-custodian task-custodian])
(thread (lambda () ...)))
...)
I ran your example, and it just returned a procedure - did you extract it out of a more complete example?
Thanks for the custodian example - I’ll experiment with that.
@popa.bogdanp the parameterization of current-custodian worked perfectly!
There must be something different in how I’m using serve
that causes spawned threads to be terminated when the request ends, but using a separate custodian is fine.