Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: lambda custom runtime #496

Open
wants to merge 15 commits into
base: main
Choose a base branch
from

Conversation

i10416
Copy link

@i10416 i10416 commented Jul 8, 2024

part of #134

This commit resumes #276 with some modifications.

The main differences between this commit and the PR above are the followings;

in terms of module structure,

  • The original feral-lambda module is split into feral-lambda-kernel and feral-lambda-runtime-binding
    • feral-lambda-kernel contains types shared across runtime
    • feral-lambda-runtime-binding contains facades for AWS Java and JS runtimes
  • AWS Runtime API stuffs are moved under runtime.api package
    • correcting Lambda-Runtime-Client-Identity to Lambda-Runtime-Cognito-Identity
    • adding LambdaRuntimeAPIClient that wraps http4s Client
  • Scala Native support is not included in the commit

in terms of behaviors,

  • the runtime runs next invocation calls and handlers in parallel edit: runtime should not run handlers in parallel.
  • the runtime will terminate when Lambda Runtime API returns 500, which implies unrecoverable container error

See also

Co-Authored-By: Scott Thomson

i10416 added 4 commits July 9, 2024 01:42
This commit resumes typelevel#276 with
some modifications.

The main differences between this commit and the PR above are the followings;

in terms of module structure,
- The original `feral-lambda` module is split into `feral-lambda-kernel`
  and `feral-lambda-runtime-binding`
    - `feral-lambda-kernel` contains types shared across runtime
    - `feral-lambda-runtime-binding` contains facades for AWS Java and
      JS runtimes
- AWS Runtime API stuffs are moved under runtime.api package
    - correcting `Lambda-Runtime-Client-Identity` to `Lambda-Runtime-Cognito-Identity`
    - adding `LambdaRuntimeAPIClient` that wraps http4s `Client`
- Scala Native support is not included in the commit

in terms of behaviors,
- the runtime runs next invocation calls and handlers in parallel
- the runtime will terminate when Lambda Runtime API returns 500, which
  implies unrecoverable container error

See also
- https://docs.aws.amazon.com/lambda/latest/dg/runtimes-api.html

Co-Authored-By: Scott Thomson
@armanbilge
Copy link
Member

the runtime runs next invocation calls and handlers in parallel

Are you sure that AWS Lambda actually support this? i.e. will the GET request for the next event return something different before you POST the result? If so, that would be violating HTTP method semantics.

@i10416
Copy link
Author

i10416 commented Jul 8, 2024

#496 (comment)

I think we should avoid running handlers in parallel...
Sorry for confusion😢

@@ -87,7 +119,8 @@ object Context extends ContextCompanionPlatform {
logStreamName: String,
identity: Option[CognitoIdentity],
clientContext: Option[ClientContext],
remainingTime: F[FiniteDuration]
remainingTime: F[FiniteDuration],
xRayTraceId: Option[String]
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

propagate X-Ray-Trace-Id to handlers via Context to workaround the limitation that environment variables couldn't be set from JVM runtime.

Comment on lines +47 to +54
client
.nextInvocation()
.flatMap(handleSingleRequest(client, settings, run))
.handleErrorWith {
case ex @ ContainerError => ex.raiseError[F, Unit]
case NonFatal(_) => ().pure
case ex => ex.raiseError
}
Copy link
Author

@i10416 i10416 Jul 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Running handlers sequentially to comply with AWS Lambda API spec and to follow other implementations.

/**
* AWS Lambda Runtime API Client
*/
private[runtime] trait LambdaRuntimeAPIClient[F[_]] {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

based on https://docs.aws.amazon.com/lambda/latest/dg/samples/runtime-api.zip

# This document describes the AWS Lambda Custom Runtime API using the OpenAPI 3.0 specification.
#
# A note on error reporting:
#
# Runtimes are free to define the format of errors that are reported to the runtime API, however,
# in order to integrate with other AWS services, runtimes must report all errors using the
# standard AWS Lambda error format:
#
# Content-Type: application/vnd.aws.lambda.error+json:
# {
#     "errorMessage": "...",
#     "errorType": "...",
#     "stackTrace": [],
# }
#
# See '#/components/schemas/ErrorRequest'.
#
# Lambda's default behavior is to use Lambda-Runtime-Function-Error-Type header value to construct an error response
# when error payload is not provided or can not be read.


openapi: 3.0.0
info:
  title: AWS Lambda Runtime API
  description: AWS Lambda Runtime API is an HTTP API for implementing custom runtimes
  version: 1.0.3

servers:
  - url: /2018-06-01

paths:

  /runtime/init/error:
    post:
      summary: >
        Non-recoverable initialization error. Runtime should exit after reporting
        the error. Error will be served in response to the first invoke.
      parameters:
        - in: header
          name: Lambda-Runtime-Function-Error-Type
          schema:
            type: string
      requestBody:
        content:
          '*/*':
            schema: {}
      responses:
        '202':
          description: Accepted
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StatusResponse'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '500':
          description: >
            Container error. Non-recoverable state. Runtime should exit promptly.

  /runtime/invocation/next:
    get:
      summary: >
        Runtime makes this HTTP request when it is ready to receive and process a
        new invoke.
      responses:
        '200':
          description: >
            This is an iterator-style blocking API call. Response contains
            event JSON document, specific to the invoking service.
          headers:
            Lambda-Runtime-Aws-Request-Id:
              description: AWS request ID associated with the request.
              schema:
                type: string
            Lambda-Runtime-Trace-Id:
              description: X-Ray tracing header.
              schema:
                type: string
            Lambda-Runtime-Client-Context:
              description: >
                Information about the client application and device when invoked
                through the AWS Mobile SDK.
              schema:
                type: string
            Lambda-Runtime-Cognito-Identity:
              description: >
                Information about the Amazon Cognito identity provider when invoked
                through the AWS Mobile SDK.
              schema:
                type: string
            Lambda-Runtime-Deadline-Ms:
              description: >
                Function execution deadline counted in milliseconds since the Unix epoch.
              schema:
                type: string
            Lambda-Runtime-Invoked-Function-Arn:
              description: >
                The ARN requested. This can be different in each invoke that
                executes the same version.
              schema:
                type: string
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EventResponse'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '500':
          description: >
            Container error. Non-recoverable state. Runtime should exit promptly.

  /runtime/invocation/{AwsRequestId}/response:
    post:
      summary: Runtime makes this request in order to submit a response.
      parameters:
        - in: path
          name: AwsRequestId
          schema:
            type: string
          required: true
      requestBody:
        content:
          '*/*':
            schema: {}
      responses:
        '202':
          description: Accepted
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StatusResponse'
        '400':
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '413':
          description: Payload Too Large
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '500':
          description: >
            Container error. Non-recoverable state. Runtime should exit promptly.

  /runtime/invocation/{AwsRequestId}/error:
    post:
      summary: >
        Runtime makes this request in order to submit an error response. It can
        be either a function error, or a runtime error. Error will be served in
        response to the invoke.
      parameters:
        - in: path
          name: AwsRequestId
          schema:
            type: string
          required: true
        - in: header
          name: Lambda-Runtime-Function-Error-Type
          schema:
            type: string
      requestBody:
        content:
          '*/*':
            schema: {}
      responses:
        '202':
          description: Accepted
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StatusResponse'
        '400':
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '500':
          description: >
            Container error. Non-recoverable state. Runtime should exit promptly.

components:
  schemas:

    StatusResponse:
      type: object
      properties:
        status:
          type: string

    ErrorResponse:
      type: object
      properties:
        errorMessage:
          type: string
        errorType:
          type: string

    ErrorRequest:
      type: object
      properties:
        errorMessage:
          type: string
        errorType:
          type: string
        stackTrace:
          type: array
          items:
            type: string

    EventResponse:
      type: object

i10416 added 4 commits July 9, 2024 21:22
Official Java and JS runtime do not expose trace id from handler `Context`.
In order to keep both pure Scala runtime context and runtime binding
context in sync, this commit modifies `ContextPlatform` constructor so that
it reads trace id from environment variables.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants