Hi. It would be extremely helpful to us if Hunchentoot had what we call a "soft shutdown". This would be like shutdown, except that any request currently in progress would continue until its reply is sent back to the client.
We want to have a comment for our own server that will do this.
We do not need for Hunchentoot to worry about cases where the request handler turns out to take forever or a very long time. We are happy to say that in such cases, we will take care of it exogenously. In our case, we'd set up a timeout and "kill -9" the Lisp in this case.
I have implemented a kludgey implementation of this for the time being. It only works for the single-threaded mode, since that's all I need, and I wanted to keep the changes as simple as possible.
I have attached the patch.
Thank you.
-- Dan
Index: lisp/libs/hunchentoot/taskmaster.lisp =================================================================== --- lisp/libs/hunchentoot/taskmaster.lisp (revision 422736) +++ lisp/libs/hunchentoot/taskmaster.lisp (working copy) @@ -128,7 +128,13 @@
(defmethod handle-incoming-connection ((taskmaster single-threaded-taskmaster) socket) ;; in a single-threaded environment we just call PROCESS-CONNECTION - (process-connection (taskmaster-acceptor taskmaster) socket)) + (let ((acceptor (taskmaster-acceptor taskmaster))) + ;; While a request is being processed, set the flag that says so. + (unwind-protect + (progn + (setf (acceptor-is-processing-p acceptor) t) + (process-connection acceptor socket)) + (setf (acceptor-is-processing-p acceptor) nil))))
(defvar *default-max-thread-count* 100) Index: lisp/libs/hunchentoot/acceptor.lisp =================================================================== --- lisp/libs/hunchentoot/acceptor.lisp (revision 422736) +++ lisp/libs/hunchentoot/acceptor.lisp (working copy) @@ -125,6 +125,14 @@ :accessor acceptor-shutdown-p :documentation "A flag that makes the acceptor shutdown itself when set to something other than NIL.") + #-:lispworks + (acceptor-is-processing-p :initform nil + :accessor acceptor-is-processing-p + :documentation "This is used with +soft shutdown. In soft shutdown, the socket is not closed +until the current request, if any, is finished. This flag +is true if we are in the middle of processing a request. +KLUDGE: THIS ONLY WORKS FOR SINGLE-THREADED TASKMASTERS") (access-logger :initarg :access-logger :accessor acceptor-access-logger :documentation "Designator for a function to call to @@ -186,9 +194,12 @@ (:documentation "Starts the ACCEPTOR so that it begins accepting connections. Returns the acceptor."))
-(defgeneric stop (acceptor) +(defgeneric stop (acceptor &optional soft) (:documentation "Stops the ACCEPTOR so that it no longer accepts -requests.")) +requests. If SOFT is true, and there is a request in progress, +wait until that request is fully processed, but meanwhile do +not accept new requests. SOFT only works for single-threaded +taskmasters."))
(defgeneric start-listening (acceptor) (:documentation "Sets up a listen socket for the given ACCEPTOR and @@ -254,10 +265,16 @@ (execute-acceptor taskmaster)) acceptor)
-(defmethod stop ((acceptor acceptor)) +(defmethod stop ((acceptor acceptor) &optional soft) (setf (acceptor-shutdown-p acceptor) t) (shutdown (acceptor-taskmaster acceptor)) #-:lispworks + (when soft + (when (acceptor-is-processing-p acceptor) + (ccl:process-wait "acceptor-no-process" + #'(lambda (acceptor) (not (acceptor-is-processing-p acceptor))) + acceptor))) + #-:lispworks (usocket:socket-close (acceptor-listen-socket acceptor)) #-:lispworks (setf (acceptor-listen-socket acceptor) nil)