Amazon web services 部署公共LispWeb应用程序
我想知道如何部署用Hunchentoot、Wookie、Woo甚至Clack编写的公共LispWeb应用程序 也就是说,假设我编写了一个包含一些文件、包等的应用程序。通常,当我在本地工作时,我只需在REPL中运行一个命令,启动服务器,然后使用Amazon web services 部署公共LispWeb应用程序,amazon-web-services,amazon-ec2,lisp,common-lisp,hunchentoot,Amazon Web Services,Amazon Ec2,Lisp,Common Lisp,Hunchentoot,我想知道如何部署用Hunchentoot、Wookie、Woo甚至Clack编写的公共LispWeb应用程序 也就是说,假设我编写了一个包含一些文件、包等的应用程序。通常,当我在本地工作时,我只需在REPL中运行一个命令,启动服务器,然后使用localhost:8000或类似的方式访问它 然而,对于将应用程序部署到生产服务器(如AWS EC2)的过程,我有点困惑。我应该以什么形式部署Lisp代码?有不同的选择吗?如果服务器需要重新启动或遇到问题,会发生什么情况 要在生产环境中运行lisp映像,可
localhost:8000
或类似的方式访问它
然而,对于将应用程序部署到生产服务器(如AWS EC2)的过程,我有点困惑。我应该以什么形式部署Lisp代码?有不同的选择吗?如果服务器需要重新启动或遇到问题,会发生什么情况 要在生产环境中运行lisp映像,可以使用以下命令从lisp代码生成fasl文件:
(compile-file "app.lisp")
通过调用sbcl运行生成的.fas文件
sbcl --noinform \
--load app.fas \
--eval "(defun main (argv) (declare (ignore argv)) (hunchentoot:start (make-instance 'hunchentoot:easy-acceptor :port 4242)))"
我发现了一个博客,其中有一个解决方案,我已经根据自己的需要对linux机器上的生产系统进行了调整。不幸的是,我再也找不到该博客的参考资料了,所以我可以向您展示我的解决方案,它是针对CCL的(而最初的解决方案是针对SBCL的),我对它更为熟悉。以下是启动系统的程序:
(require 'swank)
(require 'hunchentoot)
(defparameter *httpd-port* 9090) ; The port Hunchentoot will be listening on
(defparameter *shutdown-port* 6700) ; The port CCL will be listening for shutdown
; this port is the same used in /etc/init.d/hunchentoot
(defparameter *swank-port* 5016) ; The port used for remote interaction with slime
;; Start the Swank server
(defparameter *swank-server*
(swank:create-server :port *swank-port* :dont-close t))
(require 'YOUR-PACKAGE)
(YOUR-PACKAGE:YOUR-STARTING-FUNCTION)
(princ "Hunchentoot started on port ")
(princ *httpd-port*)
(terpri)
(let* ((socket (make-socket :connect :passive :local-host "127.0.0.1" :local-port *shutdown-port* :reuse-address t))
(stream (accept-connection socket)))
(close stream)
(close socket))
(print "Stopping Hunchentoot...")
(YOUR-PACKAGE:YOUR-STOPPING-FUNCTION)
(dolist (proc (all-processes))
(unless (equal proc *current-process*)
(process-kill proc)))
(sleep 1)
(quit)
(dolist (thread (sb-thread:list-all-threads))
(unless (equal sb-thread:*current-thread* thread)
(sb-thread:terminate-thread thread)))
(sleep 1)
(sb-ext:quit)
其思想是,通过指定swank使用的端口,您可以使用slime连接到正在运行的系统。例如,我曾多次使用它动态地更改数据库链接,这种可能性的威力给我留下了深刻的印象
运行中的系统可通过以下方式终止:
telnet 127.0.0.1 6700
并由以下内容发起:
nohup ccl -l initcclserver.lisp >& server.out &
在以前版本的脚本中,我找到了SBCL特定的部分,因此如果使用它,可以修改脚本
要接受终止连接,请执行以下操作:
(sb-bsd-sockets:socket-bind socket #(127 0 0 1) *shutdown-port*)
(sb-bsd-sockets:socket-listen socket 1)
(multiple-value-bind (client-socket addr port)
(sb-bsd-sockets:socket-accept socket)
(sb-bsd-sockets:socket-close client-socket)
(sb-bsd-sockets:socket-close socket)))
要关闭系统,请执行以下操作:
(require 'swank)
(require 'hunchentoot)
(defparameter *httpd-port* 9090) ; The port Hunchentoot will be listening on
(defparameter *shutdown-port* 6700) ; The port CCL will be listening for shutdown
; this port is the same used in /etc/init.d/hunchentoot
(defparameter *swank-port* 5016) ; The port used for remote interaction with slime
;; Start the Swank server
(defparameter *swank-server*
(swank:create-server :port *swank-port* :dont-close t))
(require 'YOUR-PACKAGE)
(YOUR-PACKAGE:YOUR-STARTING-FUNCTION)
(princ "Hunchentoot started on port ")
(princ *httpd-port*)
(terpri)
(let* ((socket (make-socket :connect :passive :local-host "127.0.0.1" :local-port *shutdown-port* :reuse-address t))
(stream (accept-connection socket)))
(close stream)
(close socket))
(print "Stopping Hunchentoot...")
(YOUR-PACKAGE:YOUR-STOPPING-FUNCTION)
(dolist (proc (all-processes))
(unless (equal proc *current-process*)
(process-kill proc)))
(sleep 1)
(quit)
(dolist (thread (sb-thread:list-all-threads))
(unless (equal sb-thread:*current-thread* thread)
(sb-thread:terminate-thread thread)))
(sleep 1)
(sb-ext:quit)
希望这能有所帮助。最近,我通过为web应用程序构建自包含的可执行文件找到了一些方法,我在(发布和部署部分)以及上的构建部分写了相关内容 我把有趣的部分复制到这里,每个资源都有更多的内容。欢迎编辑,主要是那些资源,谢谢 编辑2019年7月:我在食谱上贡献了一页: 编辑:另请参见提供专业CL支持的工具和平台列表: (已编辑)如何将web应用程序作为脚本运行 下面我将解释如何构建和运行可执行文件,但我们当然可以将应用程序作为脚本运行。在lisp文件中,说
run.lisp
,确保:
- 要加载项目的asd文件,请执行以下操作:
(加载“my project.asd”)
- 要加载其依赖项:
(ql:quickload:myproject)
- 调用其主要功能:
(给定的(我的项目:start)
是一个导出符号,否则start
)::start
(sb ext:save lisp and die#P“可执行文件的路径/名称”:toplevel#'my-app:main function:executable t)
sbext
是用于运行外部进程的SBCL扩展。见其他
(其中许多都可以在其他库中移植)
:可执行文件t
告诉您构建可执行文件而不是
形象。我们可以建立一个图像来保存当前状态
Lisp图像,稍后再使用它。特别有用,如果
我们做了很多计算密集型的工作
如果您尝试在Slime中运行此操作,您将得到一个关于线程运行的错误:
无法保存运行多个线程的core
从简单的SBCL repl运行该命令
我想您的项目具有Quicklisp依赖项。然后你必须:
- 确保在Lisp启动时安装并加载Quicklisp(您可以 已完成Quicklisp安装)
加载项目的.asd
- 安装依赖项
- 构建可执行文件
(load "my-app.asd")
(ql:quickload :my-app)
(sb-ext:save-lisp-and-die #p"my-app-binary" :toplevel #'my-app:main :executable t)
从命令行或生成文件中,使用--load
和--eval
:
build:
sbcl --non-interactive \
--load my-app.asd \
--eval '(ql:quickload :my-app)' \
--eval "(sb-ext:save-lisp-and-die #p\"my-app\" :toplevel #my-app:main :executable t)"
使用ASDF
现在我们已经了解了基本知识,我们需要一个可移植的方法。因为
版本3.1,ASDF允许这样做。它介绍了,
从.asd中读取参数的。将此添加到.asd声明中:
:build-operation "program-op" ;; leave as is
:build-pathname "<binary-name>"
:entry-point "<my-system:main-function>"
使用Roswell或Buildapp
,一位实施经理,还有很多
此外,还有rosbuild
命令,该命令应该适用于许多应用程序
实现
我们还可以通过ros安装我的应用程序
,让我们的应用程序可以通过Roswell安装。见其文件
我们将以一句话结束
这是一场经过考验的战斗
仍然流行的“SBCL或CCL应用程序”,用于配置和保存
一个可执行的公共Lisp图像”
许多应用程序都使用它(例如,
),可于
Debian:apt安装buildapp
,但现在asdf:make或Roswell不需要它
用于web应用程序
我们同样可以为我们的web应用程序构建一个自包含的可执行文件。信息技术
因此将包含一个web服务器,并能够在
命令行:
$ ./my-web-app
Hunchentoot server is started.
Listening on localhost:9003.
请注意,这将运行生产Web服务器,而不是开发Web服务器,
因此,我们可以立即在VPS上运行二进制文件,并从
外面
我们有一件事要处理,那就是找到并放置
前台正在运行的web服务器。在我们的main
函数中,我们
可以这样做:
(defun main ()
(start-app :port 9003) ;; our start-app, for example clack:clack-up
;; let the webserver run.
;; warning: hardcoded "hunchentoot".
(handler-case (bt:join-thread (find-if (lambda (th)
(search "hunchentoot" (bt:thread-name th)))
(bt:all-threads)))
;; Catch a user's C-c
(#+sbcl sb-sys:interactive-interrupt
#+ccl ccl:interrupt-signal-condition
#+clisp system::simple-interrupt-condition
#+ecl ext:interactive-interrupt
#+allegro excl:interrupt-signal
() (progn
(format *error-output* "Aborting.~&")
(clack:stop *server*)
(uiop:quit)))
(error (c) (format t "Woops, an unknown error occured:~&~a~&" c))))
我们使用了波尔多线程库((ql:quickload“波尔多线程”)
,别名bt
)和uiop
,这是ASDF so的一部分
已加载,以便以便携方式退出(uiop:quit
,使用
选择权
sudo systemctl start my-app.service
systemctl status my-app.service
journalctl -f -u my-app.service
Restart=always
[Install]
WantedBy=basic.target
sudo systemctl enable my-app.service
mmap: wanted 1040384 bytes at 0x20000000, actually mapped at 0x715fa2145000
ensure_space: failed to allocate 1040384 bytes at 0x20000000
(hint: Try "ulimit -a"; maybe you should increase memory limits.)
sudo bash -c "echo 0 > /proc/sys/kernel/randomize_va_space"
;; a little common lisp swank demo
;; while this program is running, you can connect to it from another terminal or machine
;; and change the definition of doprint to print something else out!
;; (ql:quickload :swank)
;; (ql:quickload :bordeaux-threads)
(require :swank)
(require :bordeaux-threads)
(defparameter *counter* 0)
(defun dostuff ()
(format t "hello world ~a!~%" *counter*))
(defun runner ()
(bt:make-thread (lambda ()
(swank:create-server :port 4006)))
(format t "we are past go!~%")
(loop while t do
(sleep 5)
(dostuff)
(incf *counter*)
))
(runner)
sbcl --load demo.lisp
ssh -L4006:127.0.0.1:4006 username@example.com
(defun dostuff ()
(format t "goodbye world ~a!~%" *counter*))
(setf *counter* 0)