Currently, I'm developing 2 web-based tools for my own need with hunchentoot.
Before starting hunchentoot, I want to set some special variable with let so there values will be available while hunchentoot is running.
Like :
(let ((*db-path* "my-db-file"))
(start-hunchentoot))
But, once the handlers get invoiced, they don't seam to be in the let anymore and db-path falls back to its global state (which is nil).
At the moment I'm resolving this by writing the let in every handler.
But, I want a more general approach so I will be able to run both applications with different db-path in one run-time.
Is it possible to set db-path in a way so it will be valid for one instance of hunchentoot and not the other?
The used environment is SBCL 1.2.4 on Debian Jessie.
Adding db-path
as a slot in the acceptor might be a suitable option. However, you can also write an around
method for handle-request
. Assuming *my-acceptor*
is globally bound:
(defmethod hunchentoot:handle-request :around ((acceptor (eql *my-acceptor*)) request)
(let ((*db-path* "my-db-file"))
(call-next-method)))
Of course, you don't need to specialize with EQL
, you can define your own subclass instead. The advantage of an around method over storing a configuration variable in the class instance is that you keep the benefits of using special variables, i.e. bindings are visible from everywhere in the dynamic scope.
Here is what the documentation string, visible on Lispdoc, says about handle-request
(emphasis mine):
This function is called once the request has been read and a REQUEST object has been created. Its job is to actually handle the request, i.e. to return something to the client.
Might be a good place for around methods specialized for your subclass of ACCEPTOR which bind or rebind special variables which can then be accessed by your handlers.
I encourage you to read Hunchentoot's documentation.
The behavior you observe is because:
Dynamic bindings are local to each thread, as explained in the manual:
The interaction of special variables with multiple threads is mostly as one would expect, with behaviour very similar to other implementations.
- global special values are visible across all threads;
- bindings (e.g. using LET) are local to the thread;
- threads do not inherit dynamic bindings from the parent thread
If you make your own threads, you can build a closure which binds variables as you want. You can also rely on the portable bordeaux-threads library which takes a list of bindings to be effective inside a thread.