How to use AWS SQS Locally

Posted: 12/27/2020

Softwaremill has created an SQS compatible interface that is a docker container. As long as you have docker you can run it. Here is the official repository.

docker-compose.yaml

version: "2"
    services:
      elasticmq:
        image: softwaremill/elasticmq-native
        ports:
          - '9324:9324'  #Server
          - '9325:9325'  #UI
    volumes:
      elasticmq: null

You can start the server by running the container: docker-compose up -d

You can automatically create a queue on start via config file or you can create on programmatically.

startup_script.py

import boto3
    
    VISIBILITY_TIMEOUT = "10800"  # seconds
    client = boto3.resource(
        "sqs",
        endpoint_url="http://localhost:9324",
        region_name="DOESNOTMATTER",
        aws_secret_access_key="DOESNOTMATTER",
        aws_access_key_id="DOESNOTMATTER",
        use_ssl=False,
    )
    response = client.create_queue(
        QueueName="queue1", Attributes={"VisibilityTimeout": VISIBILITY_TIMEOUT}
    )

Creating/sending messages

# using boto3.client
    
    sqs = boto3.client(
        "sqs",
        region_name="DOESNOTMATTER",
        endpoint_url="http://localhost:9324/queue/queue1",
        aws_access_key_id="DOESNOTMATTER",
        aws_secret_access_key="DOESNOTMATTER",
    )
    response = sqs.send_message(
        QueueUrl="http://localhost:9324/queue/queue1",
        MessageAttributes={
            "message_type": {"DataType": "String", "StringValue": "message_type"}
        },
        MessageBody=str("body")
    )
    
    # using boto3.resource
    
    client = boto3.resource(
        'sqs',
        endpoint_url="http://localhost:9324",
        region_name="DOESNOTMATTER",
        aws_secret_access_key='DOESNOTMATTER',
        aws_access_key_id='DOESNOTMATTER',
        use_ssl=False
    )
    queue = client.get_queue_by_name(QueueName='queue1')
    response = queue.send_message(
        MessageAttributes={
            "message_type": {"DataType": "String", "StringValue": "message_type"}
        },
        MessageBody=str("body")
    )
    response_code = response["ResponseMetadata"]["HTTPStatusCode"]
    if not (response_code >= 200 and response_code < 300):
        raise Exception(f"Non 200 response after sending message {response_code}")
    print(str(response["MessageId"]))

Polling/receiving messages

# boto3.client
    
    sqs = boto3.client(
        "sqs",
        region_name="DOESNOTMATTER",
        endpoint_url="http://localhost:9324/queue/queue1",
        aws_access_key_id="DOESNOTMATTER",
        aws_secret_access_key="DOESNOTMATTER",
    )
    response = sqs.receive_message(
        QueueUrl="http://localhost:9324/queue/queue1",
        MaxNumberOfMessages=1,
        MessageAttributeNames=["message_type"],
        VisibilityTimeout=int(VISIBILITY_TIMEOUT),  # 0 - 43200
        WaitTimeSeconds=0,  # 0 - 20 (delay of message retrieval)
    )
    message = response.get("Messages")
    
    # boto3.resource
    
    client = boto3.resource(
      'sqs',
       endpoint_url="http://localhost:9324",
       region_name="DOESNOTMATTER",
       aws_secret_access_key='DOESNOTMATTER',
       aws_access_key_id='DOESNOTMATTER',
       use_ssl=False
    )
    queue = client.get_queue_by_name(QueueName='queue1')
    response = queue.receive_messages(
        MaxNumberOfMessages=1,
        MessageAttributeNames=["message_type"],
        VisibilityTimeout=int(VISIBILITY_TIMEOUT),
        WaitTimeSeconds=0
    )
    message = response.pop()
    # ^ NOTE This message object is very different then the message object below