Stability | experimental |
---|---|
Portability | POSIX |
Safe Haskell | None |
Language | Haskell2010 |
Tools for running Haskell on AWS Lambda using Serverless.
Usage
To deploy a Haskell function on AWS Lambda:
Initialise a Serverless project in the same directory as your Stack-enabled package and install the
serverless-haskell
plugin:npm init -y npm install --save serverless serverless-haskell@x.y.z
The version of the NPM package to install must match the version of the Haskell package.
Create
serverless.yml
with the following contents:service: myservice provider: name: aws runtime: haskell functions: myfunc: handler: mypackage.mypackage-exe # Here, mypackage is the Haskell package name and mypackage-exe is the # executable name as defined in the Cabal file plugins: - serverless-haskell
- Write your
main
function usinglambdaMain
. - Add
aeson
andserverless-haskell
topackage.yaml
:
dependencies: - base >= 4.7 && < 5 - aeson - serverless-haskell
- Build and test locally using
sls invoke local
:
The serverless-haskell
plugin will build the package using Stack. Note that
the first build can take a long time. Consider adding export SLS_DEBUG=*
so
you can see what is happening.
export SLS_DEBUG=* sls invoke local -f myfunc
Use
sls deploy
to deploy the executable to AWS Lambda.The
serverless-haskell
plugin will build the package using Stack and upload it to AWS together with a JavaScript wrapper to pass the input and output from/to AWS Lambda.export SLS_DEBUG=* sls deploy
You can test the function and see the invocation results with
sls invoke -f myfunc
.
API Gateway
This plugin supports handling API Gateway requests. Declare the HTTP events
normally in serverless.yml
and use APIGateway
in the
handler to process them.
Serverless Offline can be used
for local testing of API Gateway requests. You must use --useDocker
flag so
that the native Haskell runtime works correctly.
Additional features
Configuration options are passed to the plugin under haskell
key in custom
section of serverless.yml
.
To add flags to
stack build
, specify them as an array understackBuildArgs
:custom: haskell: stackBuildArgs: - --pedantic - --allow-different-user
- Dependent system libraries not present in the AWS Lambda environment will be automatically uploaded along with the executable. Note that while statically linking the executable via Cabal options is possible, it might still require the corresponding glibc version on the AWS environment.
Stack's Docker image will be used to match the AWS Lambda Linux environment. To disable this, set
docker
key tofalse
, but beware that the resulting binary might not have the required libraries to run on Lambda.custom: haskell: docker: false
By default,
stack build
command is invoked to build all the project's executables. To only build the ones used in the handlers, setbuildAll
key tofalse
. Note that at least Stack 1.9.3 has better caching behavior when building the whole project, as it doesn't need to reconfigure the build for the individual ones every time.custom: haskell: buildAll: false
Synopsis
- lambdaMain :: (FromJSON event, ToJSON res, MonadCatch m, MonadIO m) => (event -> m res) -> m ()
- module AWSLambda.Events
Documentation
:: (FromJSON event, ToJSON res, MonadCatch m, MonadIO m) | |
=> (event -> m res) | Function to process the event |
-> m () |
Process incoming events from serverless-haskell
using a provided
function.
The handler receives the input event given to the AWS Lambda function, and its return value is returned from the function.
This is intended to be used as main
, for example:
import qualified Data.Aeson as Aeson import AWSLambda main = lambdaMain handler handler :: Aeson.Value -> IO [Int] handler evt = do putStrLn "This should go to logs" print evt pure [1, 2, 3]
The handler function can receive arbitrary JSON values from custom
invocations, or one of the events from the AWSLambda.Events module, such as
S3Event
:
import AWSLambda.Events.S3Event handler :: S3Event -> IO () handler evt = do print $ records evt
If the Lambda function needs to process several types of events, use
Alternative
to combine several handlers:
import AWSLambda import AWSLambda.Events.S3Event import Data.Aeson import Data.Aeson.Alternative main = lambdaMain $ handlerS3 `alternative` handlerCustom handlerS3 :: S3Event -> IO () handlerS3 = _ handlerCustom :: Value -> IO () handlerCustom = _
When run outside the AWS Lambda environment, the input is read as JSON from the command line, and the result of the execution is printed, also as JSON, to the standard output.
module AWSLambda.Events