1

I am working on a simple Lambda function and I was wondering if I could pass in client (dynamodb this time) to the handler, so we do not re-connect for every request.

The macro is defined here:

https://docs.rs/lambda_http/0.1.1/lambda_http/macro.lambda.html 3

My function so far:

fn main() -> Result<(), Box<dyn Error>> {
    simple_logger::init_with_level(log::Level::Debug)?;
    info!("Starting up...");
    let dynamodb_client = DynamoDbClient::new(Region::EuCentral1);
    lambda!(router);
    return Ok(());
}

fn router(req: Request, ctx: Context) -> Result<impl IntoResponse, HandlerError> {
let h_req = HReq {
    http_path: req.uri().path(),
    http_method: req.method(),
};

match h_req {
    HReq {
        http_path: "/login",
        http_method: &Method::POST,
    } => user_login(req, ctx),

    _ => {
        error!(
            "Not supported http method or path {}, {}",
            h_req.http_path, h_req.http_method
        );
        let mut resp = Response::default();
        *resp.status_mut() = StatusCode::METHOD_NOT_ALLOWED;
        Ok(resp)
    }
}

}

Is it possible to extend this macro to have a second option so I can add the client all the way down to the functions which are actually talking to the database?

Istvan
  • 7,500
  • 9
  • 59
  • 109
  • Which macro? Can you please be more specific about what you are actually asking? I don't get it, sorry. – hellow Aug 06 '19 at 09:26
  • Have you seen the link in the question? – Istvan Aug 06 '19 at 09:38
  • 1
    https://stackoverflow.com/help/how-to-ask : *"but also copy the code into the question itself. Not everyone can access external sites, and the links may break over time"* Please do that. Also you linked to the documentation of the macro, not the code itself. – hellow Aug 06 '19 at 09:52

2 Answers2

2

DynamoDB is a web service, each request to it is treated as a distinct API call.

There is no functionality to keep a client connection alive in the same way you would with a regular database connection (e.g. MySQL).

My rust knowledge is a little lacking, so I don't know if http keepalive is set by default with the DynamoDBClient, but making sure http keepalive is set will help performance.

K Mo
  • 2,125
  • 8
  • 16
  • K Mo's answer is very accurate. DynamoDB is just a service. All the low level calls (data being physically inserted to the disk) are handled by AWS. The SDK you use is just an API that will connect internally to their services, so you don't need to worry about it. Also, if both Lambda and the DynamoDB table are in the same region, saving/fetching data to/from it should be relatively fast (under 100ms). Even if there was some gain in using `http keepAlive=true` it would be irrelevant in most cases. – Thales Minussi Aug 06 '19 at 10:50
  • Maybe DynamoDB is not the right example, but in general I just want to have a stateful connection that I would like to pass in all the way to the rest of the code. Thanks for the help though. – Istvan Aug 06 '19 at 11:19
  • 1
    The easiest way is to cache the connection rather than injecting it around. I am not looking for any upvotes, but I have answered a question around caching connections in Lambda functions in the past. It is here: https://stackoverflow.com/questions/54947095/aws-lambda-mysql-caching/54947780#54947780 – Thales Minussi Aug 06 '19 at 11:29
  • Long story short: open database connections outside your function's handler so they can be reused in warm starts. – Thales Minussi Aug 06 '19 at 11:33
  • 1
    This is exactly what I would like to do, but Rust is not too friendly in this regard. I guess I will just use Arc and reference it. – Istvan Aug 06 '19 at 11:49
0

After considering all the options I decided to implement this with lazy_static.

#[macro_use]
extern crate lazy_static;

lazy_static! {
    static ref DYNAMODB_CLIENT: DynamoDbClient = DynamoDbClient::new(Region::EuCentral1);
}

This is getting instantiated at run time and can be used internally in the module without any problems.

Istvan
  • 7,500
  • 9
  • 59
  • 109