skip to Main Content

I’m trying to set up some basic CRUD function for a blog to get my feet wet with AWS. This is the lambda function I’m using:

public class StoreDataLambda implements RequestStreamHandler {

    public static final Logger LOGGER = LoggerFactory.getLogger(StoreDataLambda.class);
    private static final String DB_URL = "<my jdbc url>.us-east-2.rds.amazonaws.com:5432/postgres";
    @Override
    public void handleRequest(InputStream input, OutputStream output, Context context) throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        Connection connection = null;

        try {
            String secretName = "<mySecretName>";
            Region region = Region.of("us-east-2");

            // Create a Secrets Manager client
            SecretsManagerClient client = SecretsManagerClient.builder()
                    .region(region)
                    .build();

            GetSecretValueRequest getSecretValueRequest = GetSecretValueRequest.builder()
                    .secretId(secretName)
                    .build();

            GetSecretValueResponse getSecretValueResponse = null;

            try {
                getSecretValueResponse = client.getSecretValue(getSecretValueRequest);
            } catch (Exception e) {
                // For a list of exceptions thrown, see
                // https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_GetSecretValue.html
                LOGGER.error("Error occurred while retrieving secret value: " + e.getMessage());
                e.printStackTrace();
            }

            String secret = getSecretValueResponse.secretString();
            JsonNode secretJson = mapper.readTree(secret);
            String dbUrl = DB_URL;
            String dbUsername = secretJson.get("username").asText();
            String dbPassword = secretJson.get("password").asText();
            LOGGER.info("Attempting to connect to the DB...");
            connection = DriverManager.getConnection(dbUrl, dbUsername, dbPassword);
            JsonNode jsonInput = mapper.readTree(input);

            // Assuming JSON structure: { "title": "value1", "content": "value2" }
            String title = jsonInput.get("title").asText();
            String content = jsonInput.get("content").asText();

            // Store data into PostgreSQL using prepared statement
            String sql = "INSERT INTO blog_page.blog_post (title, content) VALUES (?, ?)";
            PreparedStatement statement = connection.prepareStatement(sql);
            statement.setString(1, title);
            statement.setString(2, content);
            statement.executeUpdate();

            // Close resources
            statement.close();
            connection.close();
        } catch (SQLException e) {
            // Handle database exceptions
            LOGGER.error("Error occurred while connecting to the database: " + e.getMessage());
            e.printStackTrace();

        } finally {
            try {
                if (connection != null && !connection.isClosed()) {
                    connection.close();
                }
            } catch (SQLException e) {
                LOGGER.error("Error occurred while closing the connection: " + e.getMessage());
                e.printStackTrace();
            }
        }
    }

The lambda function and the DB are both in the same VPC/security group/subnets and I have set up the role for the lambda such that it should provide read/write access to the DB. Whenever I test it in AWS by sending a json, it just times out after 3 seconds.

This is all I get in the logs:

2023-12-12T06:00:11.938Z 3bd24ba5-8e9e-472a-b0ef-458898205451 Task timed out after 3.01 seconds

Any ideas on where to start with troubleshooting would be greatly welcome.

2

Answers


  1. Chosen as BEST ANSWER

    So it turns out the problem was fairly simple.

    I was using this jdbc url format:

    "jdbc:postgresql:<private>.us-east-2.rds.amazonaws.com:5432/postgres"
    

    instead of this...

    "jdbc:postgresql://<private>.us-east-2.rds.amazonaws.com:5432/postgres"
    

    Correcting that solved the problem. Lambda can now talk to the DB!

    I also did some refactoring so now the debug logging works as well. In addition, it is taking quite a bit longer for the Lambda to run than I'd have imagined. The 3 second default just wasn't enough for a cold start.


  2. Merely putting resources "in the same security group" does not ensure connectivity. The rules of the Security Group are applied to each resource individually. There is no concept of resources being ‘in’ a security group.

    The preferred configuration is:

    • A security group on the Lambda function (Lambda-SG) that permits all outbound traffic
    • A security group on the database (DB-SG) that permits inbound traffic on the appropriate port (eg port 3306 for MySQL) with a source set to Lambda-SG

    That is, the DB-SG specifically references the Lambda-SG in the Inbound rule.

    Alternatively, if you wish to use a single security group (not recommended), then you will need to add a rule to that security group to permit inbound traffic from itself. This will allow all resources that use the security group to communicate with each other.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search