Skip to content

orivej/heroku-buildpack-cl

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 

Repository files navigation

Heroku Buildpack for Common Lisp

My edition of the SBCL buildpack for Heroku by Mike Travers, reworked by Anton Vodonosov.

Differences from Anton's buildpack:

  • Cache Quicklisp archives between rebuilds.
  • Streamline slug layout.
  • Simplify Procfile.
  • Provide test-run to simulate remote environment locally.

Usage

You provide heroku-compile.lisp in the root of your source tree, which downloads all external dependencies and ensures that all .lisp files are compiled to speed up deployment. The buildpack loads it with SBCL installed in the checkout of your source tree (in bin/ and lib/sbcl/) in the environment where (1) ASDF is loaded, (2) ASDF registry is empty except for the root directory of your source tree (with no recursion into subdirectories), (3) ASDF places .fasl files alongside corresponding source files, (4) (require-quicklisp) is defined to install Quicklisp in the cache directory and load it, (5) *build-dir* contains the pathname of your source tree checkout and *cache-dir* - the pathname of the cache which persists across builds. Then quicklisp/ is copied from the cache dir to the build dir.

A simple heroku-compile.lisp for my-system.asd:

(require-quicklisp)
(ql:quickload :my-system)

You provide a Procfile in the root of your source tree, which may launch SBCL from PATH.

web: sbcl --script my-launcher.lisp

The script develops its environment for itself:

(load "quicklisp/setup.lisp")
(push #p"./" asdf:*central-registry*)
(require :my-system)
(my-package:start-web-server)
(my-package:join-web-server-thread)

You create an app with this buildpack.

Suggestions

SIGTERM

Heroku sends all your processes SIGTERM when it wants to terminate their dyno. Handle it with

(sb-sys:enable-interrupt sb-posix:sigterm (lambda (sig info context) ...))

SWANK

Compile SWANK (silently):

(require-quicklisp)
(ql-dist:install (ql-dist:find-system "swank"))
(ql-impl-util:call-with-quiet-compilation
 (lambda ()
   (load (compile-file (asdf:system-relative-pathname "swank" "swank-loader.lisp")))))
(defun swank-loader::load-user-init-file ())
(setf swank-loader:*fasl-directory* swank-loader:*source-directory*)
(ql-impl-util:call-with-quiet-compilation
 (lambda ()
   (swank-loader:init :setup nil :quiet t)
   (swank-loader::compile-contribs :load nil :quiet t)))

Load and start SWANK (silently, ignoring ~/.swank in the development environment):

(load (asdf:system-relative-pathname "swank" "swank-loader.fasl"))
(defun swank-loader::load-user-init-file ())
(setf swank-loader:*fasl-directory* swank-loader:*source-directory*)
(ql-impl-util:call-with-quiet-compilation
 (lambda ()
   (swank-loader:init)))
(swank:create-server :port 4005 :dont-close t)

Simulating remote environment locally

Checkout the buildpack and from the root of your source tree, after commiting all changes, run .../heroku-buildpack-cl/bin/test-compile and then env PORT=8080 .../heroku-buildpack-cl/bin/test-run --script my-launcher.lisp

About

Streamlined edition of SBCL Heroku buildpack

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Common Lisp 95.8%
  • Shell 4.2%