Jacob Heath
Jacob Heath

Reputation: 77

how to invoke a local lambda function from sam local api

I am running a api with aws-sam that points to a flask based lambda function which is my app.

Here is the template.json for sam:

        "Flask": {
            "Type": "AWS::Serverless::Function",
            "Properties": {
                "CodeUri": "api/",
                "Handler": "app.app",
                "Tracing": "Active",
                "Events": {
                    "Whoami": {
                        "Type": "Api",
                        "Properties": {
                            "Path": "/{proxy+}",
                            "Method": "any",
                            "RestApiId": {
                                "Ref": "SibilusApi"
                            }
                        }
                    }
                }
            }
        },
        "EmailSender": {
            "Type": "AWS::Serverless::Function",
            "Properties": {
                "FunctionName": "EmailSender",
                "CodeUri": "api/",
                "Handler": 
                  "src/email_sender_lambda_function.lambda_handler",
                "Tracing": "Active"
            }
        },

I then have another lambda function, that I wish to invoke from my flask application.

I start my api with sam local start-api --docker-network sam-network.

in my app.py I have:

import json
from flask_lambda import FlaskLambda
from flask_cors import CORS
import boto3

app = FlaskLambda(__name__)
CORS(app)


@app.route("/hello", methods=["GET"])
def hello():
    print("I am running")
    lambda_client = boto3.client("lambda", endpoint_url="http://localhost:3001", use_ssl=False)
    response = lambda_client.invoke(FunctionName="EmailSender", Payload = json.dumps({"event": "hello world"}))
    print(response)
    return {"hello": "world"}, 200

I started my other lambda function locally with sam local start-lambda --docker-network sam-network

Now I have the api on http://127.0.0.1:3000 , and I have my local lambda functions running on http://127.0.0.1:3001.

If I try to invoke the local lambda function from command line with a curl on port 3001, it works fine.

When I curl my api: curl http://localhost:3000/hello the flask application executes the /hello as expected

But my flask application cannot invoke my EmailSender function runnning locally in SAM:

error message

Traceback (most recent call last):
  File "/var/task/flask/app.py", line 2073, in wsgi_app
    response = self.full_dispatch_request()
  File "/var/task/flask/app.py", line 1519, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/var/task/flask_cors/extension.py", line 165, in wrapped_function
    return cors_after_request(app.make_response(f(*args, **kwargs)))
  File "/var/task/flask/app.py", line 1517, in full_dispatch_request
    rv = self.dispatch_request()
  File "/var/task/flask/app.py", line 1503, in dispatch_request
    return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)
  File "/var/task/app.py", line 14, in hello
    response = lambda_client.invoke(FunctionName="EmailSender", Payload = json.dumps({"event": "hello world"}))
  File "/var/task/botocore/client.py", line 530, in _api_call
    return self._make_api_call(operation_name, kwargs)
  File "/var/task/botocore/client.py", line 943, in _make_api_call
    http, parsed_response = self._make_request(
  File "/var/task/botocore/client.py", line 966, in _make_request
    return self._endpoint.make_request(operation_model, request_dict)
  File "/var/task/botocore/endpoint.py", line 119, in make_request
    return self._send_request(request_dict, operation_model)
  File "/var/task/botocore/endpoint.py", line 202, in _send_request
    while self._needs_retry(
  File "/var/task/botocore/endpoint.py", line 354, in _needs_retry
    responses = self._event_emitter.emit(
  File "/var/task/botocore/hooks.py", line 412, in emit
    return self._emitter.emit(aliased_event_name, **kwargs)
  File "/var/task/botocore/hooks.py", line 256, in emit
    return self._emit(event_name, kwargs)
  File "/var/task/botocore/hooks.py", line 239, in _emit
    response = handler(**kwargs)
  File "/var/task/botocore/retryhandler.py", line 207, in __call__
    if self._checker(**checker_kwargs):
  File "/var/task/botocore/retryhandler.py", line 284, in __call__
    should_retry = self._should_retry(
  File "/var/task/botocore/retryhandler.py", line 320, in _should_retry
    return self._checker(attempt_number, response, caught_exception)
  File "/var/task/botocore/retryhandler.py", line 363, in __call__
    checker_response = checker(
  File "/var/task/botocore/retryhandler.py", line 247, in __call__
    return self._check_caught_exception(
  File "/var/task/botocore/retryhandler.py", line 416, in _check_caught_exception
    raise caught_exception
  File "/var/task/botocore/endpoint.py", line 281, in _do_get_response
    http_response = self._send(request)
  File "/var/task/botocore/endpoint.py", line 377, in _send
    return self.http_session.send(request)
  File "/var/task/botocore/httpsession.py", line 484, in send
    raise EndpointConnectionError(endpoint_url=request.url, error=e)
botocore.exceptions.EndpointConnectionError: Could not connect to the endpoint URL: "http://localhost:3001/2015-03-31/functions/EmailSender/invocations"END RequestId: fc4d80cf-ec20-414a-a2bd-c9067ba964b1

Am I doing something wrong?

I realize that the problem might be the "localhost" part in the flask application, but I haven't been able to figure out what to put instead. If I use --docker-network, and tries the docker's internal ip, it wouldn't work.

Could anyone point me in the right direction?

Upvotes: 1

Views: 589

Answers (1)

Yavako
Yavako

Reputation: 1

I faced the same problem today, and I've resolved it.

You should use host.docker.internal when you specify the endpoint URL.

Your code:

lambda_client = boto3.client("lambda", endpoint_url="http://localhost:3001", use_ssl=False)

Correct one is:

lambda_client = boto3.client("lambda", endpoint_url="http://host.docker.internal:3001", use_ssl=False)

Note: I'm using Docker Desktop on Windows.

Hope this helps you!

Upvotes: 0

Related Questions