AWS-Lambda

 view release on metacpan or  search on metacpan

Changes  view on Meta::CPAN

0.0.18 2020-06-02T19:54:22Z
    - Perl 5.30.3 and 5.28.3 are released

0.0.17 2020-04-28T10:07:10Z
    - new region Europe (Milan) eu-south-1 is available

0.0.16 2020-04-23T00:23:44Z
    - new region Africa (Cape Town) af-south-1 is available

0.0.15 2020-04-17T11:53:53Z
    - fix syntax error of POD

0.0.14 2020-04-11T11:37:43Z
    - AWS::Lambda::PSGI supports API Gateway v2 now

0.0.13 2020-03-15T00:14:09Z
    - perl 5.30.2 is released

0.0.12 2020-03-11T06:42:11Z
    - bump up AWS::XRay to 0.11

MANIFEST  view on Meta::CPAN

lib/AWS/Lambda/AL2.pm
lib/AWS/Lambda/AL2023.pm
lib/AWS/Lambda/Bootstrap.pm
lib/AWS/Lambda/Context.pm
lib/AWS/Lambda/PSGI.pm
lib/AWS/Lambda/ResponseWriter.pm
minil.toml
script/bootstrap
t/00_compile.t
t/01_echo.t
t/02_error.t
t/03_init_error.t
t/04_handler_not_found.t
t/10_lambda_next.t
t/11_lambda_response.t
t/12_lambda_error.t
t/13_lambda_init_error.t
t/14_streaming.t
t/15_lambda_response_streaming.t
t/20_psgi.t
t/21_psgi_response_streaming.t
t/lib/BootstrapMock.pm
t/test_handlers/echo.pl
t/test_handlers/error.pl
t/test_handlers/init_error.pl
t/test_handlers/streaming.pl
t/testdata/alb-base64-request.json
t/testdata/alb-get-request.json
t/testdata/alb-post-request.json
t/testdata/apigateway-base64-request.json
t/testdata/apigateway-get-request.json
t/testdata/apigateway-post-request.json
t/testdata/apigateway-v2-base64-request.json
t/testdata/apigateway-v2-get-request.json
t/testdata/apigateway-v2-post-request.json

lib/AWS/Lambda/Bootstrap.pm  view on Meta::CPAN


    my $task_root = $self->{task_root};
    my $handler = $self->{handler};
    my $name = $self->{function_name};
    return try {
        package main;
        require "${task_root}/${handler}.pl";
        my $f = main->can($name) // die "handler $name is not found";
        $self->{function} = $f;
    } catch {
        $self->lambda_init_error($_);
        $self->{function} = sub {};
        undef;
    };
}

sub handle_event {
    my $self = shift;
    $self->_init or return;
    my ($payload, $context) = $self->lambda_next;
    my $response = try {
        local $AWS::Lambda::context = $context;
        local $ENV{_X_AMZN_TRACE_ID} = $context->{trace_id};
        $self->{function}->($payload, $context);
    } catch {
        my $err = $_;
        print STDERR "$err";
        $self->lambda_error($err, $context);
        bless {}, 'AWS::Lambda::ErrorSentinel';
    };
    my $ref = ref($response);
    if ($ref eq 'AWS::Lambda::ErrorSentinel') {
        return;
    }
    if ($ref eq 'CODE') {
        $self->lambda_response_streaming($response, $context);
    } else {
        $self->lambda_response($response, $context);

lib/AWS/Lambda/Bootstrap.pm  view on Meta::CPAN

                response_url => $url,
                http         => $self->{http},
            );
            $writer->_request($content_type);
            return $writer;
        });
    } catch {
        my $err = $_;
        print STDERR "$err";
        if ($writer) {
            $writer->_close_with_error($err);
        } else {
            $self->lambda_error($err, $context);
        }
    };
    if ($writer) {
        my $response = $writer->_handle_response;
        if (!$response->{success}) {
            die "failed to response of execution: $response->{status} $response->{reason}";
        }
    }
}

sub lambda_error {
    my $self = shift;
    my ($error, $context) = @_;
    my $runtime_api = $self->{runtime_api};
    my $api_version = $self->{api_version};
    my $request_id = $context->aws_request_id;
    my $url = "http://${runtime_api}/${api_version}/runtime/invocation/${request_id}/error";
    my $type = blessed($error) // "Error";
    my $resp = $self->{http}->post($url, {
        content => encode_json({
            errorMessage => "$error",
            errorType => "$type",
        }),
    });
    if (!$resp->{success}) {
        die "failed to send error of execution: $resp->{status} $resp->{reason}";
    }
}

sub lambda_init_error {
    my $self = shift;
    my $error = shift;
    my $runtime_api = $self->{runtime_api};
    my $api_version = $self->{api_version};
    my $url = "http://${runtime_api}/${api_version}/runtime/init/error";
    my $type = blessed($error) // "Error";
    my $resp = $self->{http}->post($url, {
        content => encode_json({
            errorMessage => "$error",
            errorType => "$type",
        }),
    });
    if (!$resp->{success}) {
        die "failed to send error of execution: $resp->{status} $resp->{reason}";
    }
}

1;
__END__

=encoding utf-8

=head1 NAME

lib/AWS/Lambda/PSGI.pm  view on Meta::CPAN

        if ($key !~ /^(?:CONTENT_LENGTH|CONTENT_TYPE)$/) {
            $key = "HTTP_$key";
        }
        if (ref $value eq "ARRAY") {
            $value = join ", ", @$value;
        }
        $env->{$key} = $value;
    }

    $env->{'psgi.version'}      = [1, 1];
    $env->{'psgi.errors'}       = *STDERR;
    $env->{'psgi.run_once'}     = Plack::Util::FALSE;
    $env->{'psgi.multithread'}  = Plack::Util::FALSE;
    $env->{'psgi.multiprocess'} = Plack::Util::FALSE;
    $env->{'psgi.streaming'}    = Plack::Util::FALSE;
    $env->{'psgi.nonblocking'}  = Plack::Util::FALSE;
    $env->{'psgix.harakiri'}    = Plack::Util::TRUE;
    $env->{'psgix.input.buffered'} = Plack::Util::TRUE;

    # inject the request id that compatible with Plack::Middleware::RequestId
    if ($ctx) {

lib/AWS/Lambda/PSGI.pm  view on Meta::CPAN

    while (my ($key, $value) = each %$headers) {
        $key =~ s/-/_/g;
        $key = uc $key;
        if ($key !~ /^(?:CONTENT_LENGTH|CONTENT_TYPE)$/) {
            $key = "HTTP_$key";
        }
        $env->{$key} = $value;
    }

    $env->{'psgi.version'}      = [1, 1];
    $env->{'psgi.errors'}       = *STDERR;
    $env->{'psgi.run_once'}     = Plack::Util::FALSE;
    $env->{'psgi.multithread'}  = Plack::Util::FALSE;
    $env->{'psgi.multiprocess'} = Plack::Util::FALSE;
    $env->{'psgi.streaming'}    = Plack::Util::FALSE;
    $env->{'psgi.nonblocking'}  = Plack::Util::FALSE;
    $env->{'psgix.harakiri'}    = Plack::Util::TRUE;
    $env->{'psgix.input.buffered'} = Plack::Util::TRUE;

    # inject the request id that compatible with Plack::Middleware::RequestId
    if ($ctx) {

lib/AWS/Lambda/ResponseWriter.pm  view on Meta::CPAN

    my $self = shift;
    if ($self->{closed}) {
        # already closed
        return;
    }
    my $handle = $self->{handle};
    $self->{closed} = 1;
    return $handle->write("0\x0D\x0A\x0D\x0A");
}

sub _close_with_error {
    my ($self, $error) = @_;
    if ($self->{closed}) {
        # already closed
        return;
    }
    $self->{closed} = 1;
    my $handle = $self->{handle};
    $handle->write("0\x0D\x0A");
    my $type = blessed($error) // "Error";
    return $handle->write_header_lines({
        "lambda-runtime-function-error-type" => "$type",
        "lambda-runtime-function-error-body" => encode_base64("$error", ""),
    }, {
        "lambda-runtime-function-error-type" => "Lambda-Runtime-Function-Error-Type",
        "lambda-runtime-function-error-body" => "Lambda-Runtime-Function-Error-Body",
    });
}

1;

t/02_error.t  view on Meta::CPAN

use strict;
use warnings;
use utf8;
use Test::More;

use FindBin;
use lib "$FindBin::Bin/lib";
use BootstrapMock;

my $error;
my $bootstrap = BootstrapMock->new(
    handler     => "error.handle",
    runtime_api => "example.com",
    task_root   => "$FindBin::Bin/test_handlers",
    lambda_next => sub {
        return +{
            key1 => 1,
            key2 => 2,
            key3 => 3,
        }, undef;
    },
    lambda_error => sub {
        my $self = shift;
        $error = shift;
    },
);

ok !$bootstrap->handle_event;
like $error, qr/some error/;
done_testing;

t/03_init_error.t  view on Meta::CPAN

use warnings;
use utf8;
use Test::More;

use FindBin;
use lib "$FindBin::Bin/lib";
use BootstrapMock;
use AWS::Lambda::Context;
use Try::Tiny;

my $error;
my $bootstrap = BootstrapMock->new(
    handler     => "init_error.handle",
    runtime_api => "example.com",
    task_root   => "$FindBin::Bin/test_handlers",
    lambda_init_error => sub {
        my $self = shift;
        $error = shift;
    },
);

ok !$bootstrap->handle_event;
like $error, qr/did not return a true value/;

done_testing;

t/04_handler_not_found.t  view on Meta::CPAN

use warnings;
use utf8;
use Test::More;

use FindBin;
use lib "$FindBin::Bin/lib";
use BootstrapMock;
use AWS::Lambda::Context;
use Try::Tiny;

my $error;
my $bootstrap = BootstrapMock->new(
    handler     => "echo.handle_not_found",
    runtime_api => "example.com",
    task_root   => "$FindBin::Bin/test_handlers",
    lambda_init_error => sub {
        my $self = shift;
        $error = shift;
    },
);

ok !$bootstrap->handle_event;
like $error, qr/handler handle_not_found is not found/;

done_testing;

t/12_lambda_error.t  view on Meta::CPAN

        my $sock = shift;
        my $server = HTTP::Server::PSGI->new(
            listen_sock => $sock,
        );
        $server->run(sub {
            my $env = shift;
            my $req = Plack::Request->new($env);
            is $req->method, "POST", "http method";
            my $body = $req->body;
            my $response = decode_json(<$body>);
            cmp_deeply $response, {errorMessage=>"some error 😨", errorType=>'Error'}, "response";
            my $res = $req->new_response(200);
            $res->finalize;
        });
    },
    max_wait => 10, # seconds
);

my $bootstrap = AWS::Lambda::Bootstrap->new(
    handler     => "echo.handle",
    runtime_api => "example.com",
    task_root   => "$FindBin::Bin/test_handlers",
    runtime_api => "127.0.0.1:" . $app_server->port,
);

my $error = "some error 😨";
my $context = AWS::Lambda::Context->new(
    deadline_ms => 1542409706888,
    aws_request_id => "8476a536-e9f4-11e8-9739-2dfe598c3fcd",
    invoked_function_arn => 'arn:aws:lambda:us-east-2:123456789012:function:custom-runtime',
);
$bootstrap->lambda_error($error, $context);
$app_server->stop;

done_testing;

t/13_lambda_init_error.t  view on Meta::CPAN

        my $sock = shift;
        my $server = HTTP::Server::PSGI->new(
            listen_sock => $sock,
        );
        $server->run(sub {
            my $env = shift;
            my $req = Plack::Request->new($env);
            is $req->method, "POST", "http method";
            my $body = $req->body;
            my $response = decode_json(<$body>);
            cmp_deeply $response, {errorMessage=>"some error 😨", errorType=>'Error'}, "response";
            my $res = $req->new_response(200);
            $res->finalize;
        });
    },
    max_wait => 10, # seconds
);

my $bootstrap = AWS::Lambda::Bootstrap->new(
    handler     => "echo.handle",
    runtime_api => "example.com",
    task_root   => "$FindBin::Bin/test_handlers",
    runtime_api => "127.0.0.1:" . $app_server->port,
);

my $error = "some error 😨";
$bootstrap->lambda_init_error($error);
$app_server->stop;

done_testing;

t/lib/BootstrapMock.pm  view on Meta::CPAN


our @ISA = qw(AWS::Lambda::Bootstrap);

sub new {
    my $class = shift;
    my %args = @_;
    my $self = $class->SUPER::new(%args);
    $self->{lambda_next}               = $args{lambda_next}               // sub { die "unexpected call of lambda_next" };
    $self->{lambda_response}           = $args{lambda_response}           // sub { die "unexpected call of lambda_response" };
    $self->{lambda_response_streaming} = $args{lambda_response_streaming} // sub { die "unexpected call of lambda_response_streaming" };
    $self->{lambda_error}              = $args{lambda_error}              // sub { die "unexpected call of lambda_error" };
    $self->{lambda_init_error}         = $args{lambda_init_error}         // sub { die "unexpected call of lambda_init_error" };
    return $self;
}

sub lambda_next {
    my $self = shift;
    return $self->{lambda_next}->($self, @_);
}

sub lambda_response {
    my $self = shift;
    return $self->{lambda_response}->($self, @_);
}

sub lambda_response_streaming {
    my $self = shift;
    return $self->{lambda_response_streaming}->($self, @_);
}

sub lambda_error {
    my $self = shift;
    return $self->{lambda_error}->($self, @_);
}

sub lambda_init_error {
    my $self = shift;
    return $self->{lambda_init_error}->($self, @_);
}

1;

t/test_handlers/error.pl  view on Meta::CPAN

use utf8;
use strict;
use warnings;

sub handle {
    die "some error";
}

1;



( run in 0.823 second using v1.01-cache-2.11-cpan-65fba6d93b7 )