|
1 | 1 | module Aws.Lambda.Runtime |
2 | 2 | ( runLambda |
| 3 | + , Runtime.Mode(..) |
| 4 | + , Runtime.LambdaResult(..) |
3 | 5 | ) where |
4 | 6 |
|
5 | 7 | import Control.Exception.Safe.Checked |
| 8 | +import Control.Monad (forever) |
6 | 9 | import qualified Network.HTTP.Client as Http |
7 | 10 |
|
| 11 | +import Data.Aeson |
| 12 | +import qualified Data.ByteString.Lazy.Char8 as LazyByteString |
| 13 | + |
8 | 14 | import qualified Aws.Lambda.Runtime.ApiInfo as ApiInfo |
9 | 15 | import qualified Aws.Lambda.Runtime.Context as Context |
10 | 16 | import qualified Aws.Lambda.Runtime.Environment as Environment |
11 | 17 | import qualified Aws.Lambda.Runtime.Error as Error |
12 | 18 | import qualified Aws.Lambda.Runtime.IPC as IPC |
13 | 19 | import qualified Aws.Lambda.Runtime.Publish as Publish |
| 20 | +import qualified Aws.Lambda.Runtime.Common as Runtime |
14 | 21 |
|
15 | 22 | -- | Runs the user @haskell_lambda@ executable and posts back the |
16 | | --- results |
17 | | -runLambda |
18 | | - :: Http.Manager |
19 | | - -> IO () |
20 | | -runLambda manager = do |
21 | | - lambdaApi <- Environment.apiEndpoint `catch` variableNotSet |
22 | | - event <- ApiInfo.fetchEvent manager lambdaApi `catch` errorParsing |
23 | | - context <- Context.initialize event `catch` errorParsing `catch` variableNotSet |
24 | | - ((invokeAndRun manager lambdaApi event context |
25 | | - `catch` \err -> Publish.parsingError err lambdaApi context manager) |
26 | | - `catch` \err -> Publish.invocationError err lambdaApi context manager) |
27 | | - `catch` \(err :: Error.EnvironmentVariableNotSet) -> Publish.runtimeInitError err lambdaApi context manager |
| 23 | +-- results. This is called from the layer's @main@ function. |
| 24 | +runLambda :: Runtime.Mode -> IO () |
| 25 | +runLambda mode = do |
| 26 | + manager <- Http.newManager httpManagerSettings |
| 27 | + forever $ do |
| 28 | + lambdaApi <- Environment.apiEndpoint `catch` variableNotSet |
| 29 | + event <- ApiInfo.fetchEvent manager lambdaApi `catch` errorParsing |
| 30 | + context <- Context.initialize event `catch` errorParsing `catch` variableNotSet |
| 31 | + ((invokeAndRun mode manager lambdaApi event context |
| 32 | + `catch` \err -> Publish.parsingError err lambdaApi context manager) |
| 33 | + `catch` \err -> Publish.invocationError err lambdaApi context manager) |
| 34 | + `catch` \(err :: Error.EnvironmentVariableNotSet) -> Publish.runtimeInitError err lambdaApi context manager |
| 35 | + |
| 36 | +httpManagerSettings :: Http.ManagerSettings |
| 37 | +httpManagerSettings = |
| 38 | + -- We set the timeout to none, as AWS Lambda freezes the containers. |
| 39 | + Http.defaultManagerSettings |
| 40 | + { Http.managerResponseTimeout = Http.responseTimeoutNone |
| 41 | + } |
28 | 42 |
|
29 | 43 | invokeAndRun |
30 | 44 | :: Throws Error.Parsing |
31 | 45 | => Throws Error.Invocation |
32 | 46 | => Throws Error.EnvironmentVariableNotSet |
33 | | - => Http.Manager |
| 47 | + => Runtime.Mode |
| 48 | + -> Http.Manager |
34 | 49 | -> String |
35 | 50 | -> ApiInfo.Event |
36 | 51 | -> Context.Context |
37 | 52 | -> IO () |
38 | | -invokeAndRun manager lambdaApi event context = do |
39 | | - result <- IPC.invoke (ApiInfo.event event) context |
| 53 | +invokeAndRun mode manager lambdaApi event context = do |
| 54 | + result <- invokeWithMode mode event context |
40 | 55 | Publish.result result lambdaApi context manager |
41 | 56 | `catch` \err -> Publish.invocationError err lambdaApi context manager |
42 | 57 |
|
| 58 | +invokeWithMode |
| 59 | + :: Throws Error.Invocation |
| 60 | + => Throws Error.Parsing |
| 61 | + => Throws Error.EnvironmentVariableNotSet |
| 62 | + => Runtime.Mode |
| 63 | + -> ApiInfo.Event |
| 64 | + -> Context.Context |
| 65 | + -> IO Runtime.LambdaResult |
| 66 | +invokeWithMode mode event context = |
| 67 | + case mode of |
| 68 | + Runtime.IPC -> IPC.invoke (ApiInfo.event event) context |
| 69 | + (Runtime.DirectCall f) -> do |
| 70 | + handlerName <- Environment.handlerName |
| 71 | + let lambdaOptions = Runtime.LambdaOptions |
| 72 | + { eventObject = LazyByteString.unpack $ ApiInfo.event event |
| 73 | + , contextObject = LazyByteString.unpack . encode $ context |
| 74 | + , functionHandler = handlerName |
| 75 | + , executionUuid = "" -- DirectCall doesnt use UUID |
| 76 | + } |
| 77 | + result <- f lambdaOptions |
| 78 | + case result of |
| 79 | + Left err -> |
| 80 | + throw $ Error.Invocation err |
| 81 | + Right value -> |
| 82 | + pure value |
| 83 | + |
43 | 84 | variableNotSet :: Error.EnvironmentVariableNotSet -> IO a |
44 | 85 | variableNotSet (Error.EnvironmentVariableNotSet env) = |
45 | 86 | error ("Error initializing, variable not set: " <> env) |
|
0 commit comments