'GoneException when calling post_to_connection on AWS lambda and API gateway

I want to send a message to a websocket client when it connects to the server on AWS lambda and API gateway. Currently, I use wscat as a client. Since the response 'connected' is not shown on the wscat console when I connect to the server, I added post_to_connection to send a message 'hello world' to the client. However, it raises GoneException.

An error occurred (GoneException) when calling the PostToConnection operation

How can I solve this problem and send some message to wscat when connecting to the server?

My python code is below. I use Python 3.8.5.

import os
import boto3
import botocore

dynamodb = boto3.resource('dynamodb')
connections = dynamodb.Table(os.environ['TABLE_NAME'])

def lambda_handler(event, context):
    domain_name = event.get('requestContext',{}).get('domainName')
    stage       = event.get('requestContext',{}).get('stage')
    connection_id = event.get('requestContext',{}).get('connectionId')
    result = connections.put_item(Item={ 'id': connection_id })

    apigw_management = boto3.client('apigatewaymanagementapi',
                            endpoint_url=F"https://{domain_name}/{stage}")
    ret = "hello world";

    try:
      _ = apigw_management.post_to_connection(ConnectionId=connection_id,
                                             Data=ret)
    except botocore.exceptions.ClientError as e:
      print(e);
      return { 'statusCode': 500,
                    'body': 'something went wrong' }

    return { 'statusCode': 200,
             "body": 'connected'};


Solution 1:[1]

Self-answer: you cannot post_to_connection to the connection itself in onconnect.

Solution 2:[2]

I have found that the GoneException can occur when the client that initiated the websocket has disconnected from the socket and its connectionId can no longer be found. Is there something causing the originating client to disconnect from the socket before it can receive your return message?

My use case is different but I am basically using a DB to check the state of a connection before replying to it, and not using the request context to do that. This error's appearance was reduced by writing connectionIds to DynamoDB on connect, and deleting them from the table upon disconnect events. Messaging now writes to connectionIds in the table instead of the id in the request context. Most messages go through but some errors are still emitted when the client leaves the socket but does not emit a proper disconnect event which leaves orphans in the table. The next step is to enforce item deletes when irregular disconnections occur. Involving a DB may be overkill for your situation, just sharing what helped me make progress on the GoneException error.

Solution 3:[3]

We need to post to connection after connecting (i.e. when the routeKey is not $connect)

routeKey = event.get('requestContext', {}).get('routeKey')
print(routeKey)  # for debugging 

if routeKey != '$connect':  # if we have defined multiple route keys we can choose the right one here
  apigw_management.post_to_connection(ConnectionId=connection_id, Data=ret)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 nemy
Solution 2 massif
Solution 3