Search code examples
amazon-s3aws-lambdaimage-compression

How to know whether lambda image compression is completed?


I'm making a GraphQL API server with apollo-server-express.

To allow users to upload their image to S3, I made a mutation called userContentFileUpload Mutation which schema looks like:

type Mutation {
  userContentFileUpload(file: File!) {
    uploadUrl
    fileUrl
  }
}

uploadUrl is a pre-signed S3 URL for uploading image file and fileUrl is a S3 URL including a key which the uploaded image file will have.

So a client could use this API as follows:

  1. Upload image file to uploadUrl using fetch or axios.
  2. Wait until the upload request successes.
  3. Use the fileUrl as remote URL of the uploaded file.

Now I'm trying to add an AWS lambda function that compresses uploaded images.

The lambda function will:

  1. Triggered by a S3 file upload event.
  2. Compress the uploaded file.
  3. Put compressed file to the S3 bucket.

However, since the upload request to uploadUrl will be completed before the step 1 of lambda function, there will be a gap between the time that client start using fileUrl and the time that the compressed file actually get put to the S3 bucket.

How can I fill this gap??


Solution

  • As far as I can tell, you have two general options now:

    1. Compress the image when you receive it (called static rendition).
    2. Compress the image when you deliver it and cache the result (sometimes called dynamic rendition).

    Those are the two options you have in all asset delivery systems. Both approaches have their advantages and disadvantages.

    Since you did not provide a lot of details (image size, usage patterns etc), it is hard to say which of the two is better for you.

    Therefore, I will just give you hints how both could be implemented in AWS.

    If you want to compress the image when you receive it and only want to allow access to fileUrl when the image is compressed, you could switch to Step Functions. Since a few months API Gateway allows you to send incoming requests directly to express Step Functions for processing. So you could create a Step Function that downloads the image, creates the compressed version and then returns to the caller. Obviously, this has limits. The larger the image, the longer processing might take and you might run in timeouts etc. So uploading images with 2MB, no problem. Uploading images that are 1GB large, that might become an issue.

    Your second option is to compress on delivery and cache the result. If you use AWS Cloudfront, you can use Lambda@Edge to do this. But you could also use S3 Object Lambdas.

    There are probably a few more options how you could build something like this. But without a lot more detail, it is hard to find the best solution for you.