4

How do I keep an API Gateway Websocket API with a Lambda Java back end from timing out after 30 seconds?

The AWS API Gateway and re:invent videos mention using pings or heartbeats to keep the Websocket connection alive but I haven't found a straight-forward working example (in Java). The front end is using HTML 5 Websockets (vanilla javascript).

I'm including my Lambda test driver in Java. It causes the API Gateway WS API to timeout after 30 seconds as documented. The driver will return successfully if you remove the delay. Any help is appreciated...

import java.io.InputStream;
import java.io.OutputStream;
import java.util.Map;

import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestStreamHandler;
import com.fasterxml.jackson.databind.ObjectMapper;

public class TestWSClient implements RequestStreamHandler {

    public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context) {
        try {
            //
            // How do we keep API Gateway from timing out after 30 seconds?
            // Is something like this even needed in the lambda?
            //
            new Thread(() -> {
                while(true) {    
                    try {
                        // Ping client every 15 seconds
                        Thread.sleep(15000);
                        //outputStream.write(); // What to write -- 0x89 0x00?
                        outputStream.flush();
                    } catch(Exception e) { e.printStackTrace(); }
                }
            }).start();

            //
            // Simulate long processing time or streaming
            //
            // NOTE: commenting sleep enables service to return w/o a timeout
            //       connection from API Gateway
            //
            try { Thread.sleep(60000); } catch(Exception e) {}

            var response = Map.of(
                "statusCode", 200,
                "headers", Map.of("Content-Type", "text/csv"),
                "body", "Hello,World"
            );

            ObjectMapper om = new ObjectMapper();

            outputStream.write(om.writeValueAsBytes(response));
            outputStream.flush();
        } catch(Exception e) { e.printStackTrace(); }
        finally { try { outputStream.close(); } catch(Exception e) {} }
    }
}
1
  • You have many issues here. You are using Thread.sleep (never put a lambda to sleep). You are handling an input stream, but you don't ever read it. Your handler should read the input and write some output. Unless you want bespoke message serialization, you probably should use the normal RequestHandler which receives ws messages from lines of JSON on the socket. Commented Dec 14, 2023 at 10:28

3 Answers 3

4

I do not think I understand your problem correctly but here is how WebSocket API work in my experience. client(s) <-(1)-> API Gateway <-(2)-> Lambda

1) is the web socket connection which stays open for a maximum of 2 hours, with idle timeout of 10 minutes as mentioned here. https://docs.aws.amazon.com/apigateway/latest/developerguide/limits.html

2 )communication is managed using @connection https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-how-to-call-websocket-api-connections.html

I believe you want to use @connection for talking to your API Gateway from lambda.

Sign up to request clarification or add additional context in comments.

8 Comments

Thanks vijtrip2, I suspect we're missing the @connection relationship. We'll look into that. BUT, we've successfully established client -> API GW -> Lambda as noted. The issue is the API GW 30 second timeout. In the Java Lambda code you'll see there is a 60 second delay. That delay causes the API Gateway to timeout the connection after 30 seconds (see API GW docs). Once that happens we can't send any more data back to the client.
This response did lead me down the right path! Searching for more info about the "@connection" I found a thread on AWS Forums that included code that got me up and running: forums.aws.amazon.com/thread.jspa?messageID=891900&
"That delay causes the API Gateway to timeout the connection after 30 seconds " -> Yes, APIGateway has the maximum integration timeout of 29 seconds. and Glad to see you are unblocked.
@user2536502 yo, so if I understood correctly you managed to circumvent the 29s integration timeout by using "@connection" responses? Or is that unrelated? I checked the thread u linked but I got a bit lost, especially cause I know squat about Java
@user2536502 Could you kindly share the solution to this question if you ever managed to resolve it?
|
0

I just faced the same problem. And I discovered that even with the websocket connection open for until 2h, the processing of the API (first lambda called) will timeout in 29s.

To workaround that, you must use an async strategy. So, create a proxy that will receive the input and call the desired lambda through an SNS topic or an SQS queue.

For more info, this link is very useful: https://repost.aws/questions/QUFXpcneknSgmhseduEh18dw/api-gateway-websocket-api-30s-timeout

Comments

-2

It looks like a NAT Gateway is required for a Lambda to call the postToConnection function provided by the AWS ApiGatewayManagementApi SDK.

Its a shame this requirement isn't specified anywhere regarding Websockets API or API Gateway.

Search for 'NAT' on this page, and read that sentence:

1 Comment

Not true. NAT is not needed. In the link reference above, they had to use NAT because their ElastiCache is located in a VPC.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.