reblocks
reblocks copied to clipboard
Calling (update mywidget) from a new thread
How to make a new thread aware of the session it was created from ?
(:input :type "button" :value "Add random task (with (update) called from a different thread)" :onclick
(weblocks/actions:make-js-action
(lambda (&rest args )
(add-task task-list (format nil "~A" (random 1001)))
(bt:make-thread
(lambda ()
(weblocks/dependencies:with-collected-dependencies
(sleep 0.5)
(update task-list) ; ERROR: Session was not created for this request!
))))))
complete executable code to illustrate the problem: https://gist.github.com/bamboospirit/e6ad95503ec40d2c7649f4aa14ad4979#file-thr-update-lisp
There are two problems with this code.
To make the session variable available in the new thread, you need to provide initial bindings to a new thread like that:
CL-USER> (let ((weblocks/session::*session* :test-value))
(bt:make-thread (lambda ()
(format t "Session in thread: ~A~%"
weblocks/session::*session*))))
Session in thread: NIL
but
CL-USER> (let ((weblocks/session::*session* :test-value))
(bt:make-thread (lambda ()
(format t "Session in thread: ~A~%"
weblocks/session::*session*))
:initial-bindings
(list* (cons 'weblocks/session::*session*
weblocks/session::*session*)
bt:*default-special-bindings*)))
Session in thread: TEST-VALUE
However, this will not solve the second issue:
When you'll call the update
method in the thread, it will have no effect, because Weblocks already sent a response to the browser.
When you call to action and update
is called the thread which processes the HTTP request, then a HTML with a new widget representation is sent in response to the action. With update
in a separate thread, this will not work, because you need an additional channel to send an update to the client-side.
Currently, this task only can be done with a WebSocket.
Got it. https://github.com/40ants/weblocks-websocket did the job