<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/your-sqs-consumer-can-hang-forever-by-default-and-the-one-timeout-that-fixes-it-iuxrtit8n" -->

---
title: Your SQS consumer can hang forever by default, and the...
description: The AWS Rust SDK allows SQS long-poll receive calls to hang indefinitely when a TCP connection is silently dropped by a load balancer or NAT gateway. Since the...
canonical: https://daily.dev/posts/your-sqs-consumer-can-hang-forever-by-default-and-the-one-timeout-that-fixes-it-iuxrtit8n
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: Your SQS consumer can hang forever by default, and the one timeout that fixes it | daily.dev
og:description: The AWS Rust SDK allows SQS long-poll receive calls to hang indefinitely when a TCP connection is silently dropped by a load balancer or NAT gateway. Since the...
og:url: https://daily.dev/posts/your-sqs-consumer-can-hang-forever-by-default-and-the-one-timeout-that-fixes-it-iuxrtit8n
og:image: https://api.daily.dev/og/posts/iuxRTit8n.png
og:image:alt: Your SQS consumer can hang forever by default, and the one timeout that fixes it
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Your SQS consumer can hang forever by default, and the one timeout that fixes it

**[Encore](https://daily.dev/sources/encore-blog)** · 5 min read · 19 upvotes · 4 comments

## Summary

The AWS Rust SDK allows SQS long-poll receive calls to hang indefinitely when a TCP connection is silently dropped by a load balancer or NAT gateway. Since the default SDK configuration only bounds connection establishment — not in-flight requests — a stalled receive never resolves, parking the entire sequential fetch loop and causing the queue to back up while the consumer appears healthy. The fix is setting an `operation_attempt_timeout` slightly above the long-poll wait time (20s + 10s headroom = 30s), which causes stalled attempts to fail and retry on a fresh connection rather than hanging forever. The distinction between `operation_attempt_timeout` (per HTTP attempt) and `operation_timeout` (entire operation including retries) is critical: only the per-attempt variant allows recovery via retry rather than giving up entirely. This issue is known to the AWS SDK team and the default is not being changed, so any service long-polling SQS with this SDK must set the timeout manually.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://encore.dev/blog/message-queue-hangs>

## Questions this post answers

### Why does my SQS consumer using the AWS Rust SDK hang forever with no errors and no restarts?

The AWS Rust SDK sets no default timeout on an individual request attempt, only on connection establishment. If a load balancer or NAT gateway silently drops an idle TCP connection while a long-poll ReceiveMessage call is in flight, the request never gets a response and never resolves, so a sequential fetch loop parks forever. Retries never trigger because they only fire on an error, and this call never returns one, so the process looks healthy while the queue backs up.

_Debugging a queue that silently stalls, daily.dev surfaces write-ups like this on AWS SDK timeout defaults._

### What operation_attempt_timeout value should I set for an SQS long-poll receive in the AWS Rust SDK?

Set operation_attempt_timeout to the long-poll wait_time_seconds plus about 10 seconds of headroom, for example 30 seconds when the long poll waits 20 seconds. It must exceed the long-poll duration so an empty poll isn't mistaken for a stall, while still being short enough to abandon a genuinely stuck request; an abandoned attempt is treated as retryable so the SDK retries on a fresh connection.

_Anyone tuning AWS SDK timeout configs for reliability finds these concrete values on daily.dev._

### What's the difference between operation_attempt_timeout and operation_timeout in the AWS SDK?

operation_attempt_timeout bounds a single HTTP attempt, so one stalled try fails and the SDK retries the operation on a fresh connection while the loop keeps moving. operation_timeout instead bounds the entire operation including all its retries, so to accommodate a 20-second long poll plus retries it must be set generously, meaning a long wait before it fires, and when it does fire it abandons the whole operation rather than letting it recover.

_Choosing between AWS SDK timeout configs is easier when developers compare real trade-offs on daily.dev._

## Community discussion

Top comments from developers on daily.dev.

**@trevorsuna** · 1 upvotes

> A healthy process with a silently stalled receive loop is a nasty failure mode. Setting the per-attempt timeout just above the long-poll window makes sense because retries can establish a fresh connection; a whole-operation timeout would throw away that recovery path.

**@agustinbarrientos** · 0 upvotes

> Maybe per-attempt timeouts should be the first example in every SQS consumer template, because a request that never fails never reaches the retry policy.

**@taiwofrancis** · 0 upvotes

> This is why resilience needs intentional configuration.

**@jenueldev** · 0 upvotes

> The per-attempt timeout fixes self-recovery, but it also exposes an observability gap: process health doesn’t prove the receive loop is advancing. Tracking the last successful poll and oldest-message age, with alerts on timeout or retry spikes, would turn this silent backlog mode into a diagnosable signal instead of waiting for queue depth alone.

## Similar posts on daily.dev

- [Retry Smarter, Not Harder](https://daily.dev/posts/retry-smarter-not-harder-oavzcpjcg) · Medium · 3 upvotes · 0 comments
- [The reliability cost of default timeouts](https://daily.dev/posts/the-reliability-cost-of-default-timeouts-1uhreyzlv) · InfoWorld · 1 upvotes · 0 comments
- [Saturation at GitHub: the saga continues](https://daily.dev/posts/saturation-at-github-the-saga-continues-2uymwgoad) · Surfing Complexity · 6 upvotes · 0 comments
- [All Your GUCs in a Row: idle\_in\_transaction\_session\_timeout](https://daily.dev/posts/all-your-gucs-in-a-row-idle-in-transaction-session-timeout-uzk5lzuwc) · Planet PostgreSQL · 1 upvotes · 0 comments
- [Why Queues Don’t Fix Overload \(And What To Do Instead\)](https://daily.dev/posts/why-queues-don-t-fix-overload-and-what-to-do-instead--z9coej1wx) · P99 Conf · 0 upvotes · 0 comments

---

Tags: [#aws](https://daily.dev/tags/aws), [#architecture](https://daily.dev/tags/architecture), [#rust](https://daily.dev/tags/rust)

[View this post on daily.dev](https://daily.dev/posts/your-sqs-consumer-can-hang-forever-by-default-and-the-one-timeout-that-fixes-it-iuxrtit8n)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"Your SQS consumer can hang forever by default, and the one timeout that fixes it","url":"https://daily.dev/posts/your-sqs-consumer-can-hang-forever-by-default-and-the-one-timeout-that-fixes-it-iuxrtit8n","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/your-sqs-consumer-can-hang-forever-by-default-and-the-one-timeout-that-fixes-it-iuxrtit8n"},"datePublished":"2026-08-05T11:27:09.728Z","dateModified":"2026-09-13T18:54:14.807Z","description":"The AWS Rust SDK allows SQS long-poll receive calls to hang indefinitely when a TCP connection is silently dropped by a load balancer or NAT gateway. Since the...","image":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/384efae20a7f3cb9a355eaff2959fabe?_a=AQAEuop","thumbnailUrl":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/384efae20a7f3cb9a355eaff2959fabe?_a=AQAEuop","isAccessibleForFree":true,"articleSection":"Encore","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"Encore","logo":"https://media.daily.dev/image/upload/s--8Bz0eBFn--/f_auto,q_auto/v1780213589/logos/encore-blog?_a=BAMAMiWQ0","url":"https://daily.dev/sources/encore-blog"},"commentCount":4,"discussionUrl":"https://daily.dev/posts/your-sqs-consumer-can-hang-forever-by-default-and-the-one-timeout-that-fixes-it-iuxrtit8n","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":19},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":4}],"keywords":"aws,architecture,rust","timeRequired":"PT5M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"Encore","item":"https://daily.dev/sources/encore-blog"},{"@type":"ListItem","position":3,"name":"Your SQS consumer can hang forever by default, and the one timeout that fixes it"}]}
{"@context":"https://schema.org","@type":"WebPage","@id":"https://daily.dev/posts/your-sqs-consumer-can-hang-forever-by-default-and-the-one-timeout-that-fixes-it-iuxrtit8n","comment":[{"@type":"Comment","text":"A healthy process with a silently stalled receive loop is a nasty failure mode. Setting the per-attempt timeout just above the long-poll window makes sense because retries can establish a fresh connection; a whole-operation timeout would throw away that recovery path.","datePublished":"2026-08-06T02:38:41.779Z","url":"https://daily.dev/posts/iuxRTit8n#c-bU86XAnoI","author":{"@type":"Person","name":"Trevor Suna","url":"https://daily.dev/trevorsuna","image":"https://media.daily.dev/image/upload/s--dZ7gXxpp--/f_auto/v1784081551/avatars/avatar_EMoP47rpuw8DNjhp6R1b6?_a=BAMAMicg0"},"interactionStatistic":{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":1}},{"@type":"Comment","text":"Maybe per-attempt timeouts should be the first example in every SQS consumer template, because a request that never fails never reaches the retry policy.","datePublished":"2026-08-06T17:49:31.146Z","url":"https://daily.dev/posts/iuxRTit8n#c-pMTmOCFGa","author":{"@type":"Person","name":"Agustin Barrientos","url":"https://daily.dev/agustinbarrientos","image":"https://media.daily.dev/image/upload/s--5ayxQnqn--/f_auto/v1788281802/avatars/avatar_wQYYVe5Tbj0NJ7C7qPoa8?_a=BAMAMicg0"}},{"@type":"Comment","text":"This is why resilience needs intentional configuration.","datePublished":"2026-08-06T02:33:32.002Z","url":"https://daily.dev/posts/iuxRTit8n#c-8BJbK1cAH","author":{"@type":"Person","name":"Taiwo Francis Oguntade","url":"https://daily.dev/taiwofrancis","image":"https://media.daily.dev/image/upload/s--px3_Pvo4--/f_auto/v1785515368/avatars/avatar_FStpm3ZejUD3qGlEeoOUS?_a=BAMAMicg0"}},{"@type":"Comment","text":"The per-attempt timeout fixes self-recovery, but it also exposes an observability gap: process health doesn’t prove the receive loop is advancing. Tracking the last successful poll and oldest-message age, with alerts on timeout or retry spikes, would turn this silent backlog mode into a diagnosable signal instead of waiting for queue depth alone.","datePublished":"2026-08-06T04:32:42.269Z","url":"https://daily.dev/posts/iuxRTit8n#c-NEsPs1iPV","author":{"@type":"Person","name":"Jenuel Oras Ganawed","url":"https://daily.dev/jenueldev","image":"https://media.daily.dev/image/upload/s--BadmiNyj--/f_auto/v1787625077/avatars/avatar_JJtZr4Sjm?_a=BAMAMicg0"}}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/your-sqs-consumer-can-hang-forever-by-default-and-the-one-timeout-that-fixes-it-iuxrtit8n#faq","mainEntity":[{"@type":"Question","name":"Why does my SQS consumer using the AWS Rust SDK hang forever with no errors and no restarts?","acceptedAnswer":{"@type":"Answer","text":"The AWS Rust SDK sets no default timeout on an individual request attempt, only on connection establishment. If a load balancer or NAT gateway silently drops an idle TCP connection while a long-poll ReceiveMessage call is in flight, the request never gets a response and never resolves, so a sequential fetch loop parks forever. Retries never trigger because they only fire on an error, and this call never returns one, so the process looks healthy while the queue backs up. Debugging a queue that silently stalls, daily.dev surfaces write-ups like this on AWS SDK timeout defaults."}},{"@type":"Question","name":"What operation_attempt_timeout value should I set for an SQS long-poll receive in the AWS Rust SDK?","acceptedAnswer":{"@type":"Answer","text":"Set operation_attempt_timeout to the long-poll wait_time_seconds plus about 10 seconds of headroom, for example 30 seconds when the long poll waits 20 seconds. It must exceed the long-poll duration so an empty poll isn't mistaken for a stall, while still being short enough to abandon a genuinely stuck request; an abandoned attempt is treated as retryable so the SDK retries on a fresh connection. Anyone tuning AWS SDK timeout configs for reliability finds these concrete values on daily.dev."}},{"@type":"Question","name":"What's the difference between operation_attempt_timeout and operation_timeout in the AWS SDK?","acceptedAnswer":{"@type":"Answer","text":"operation_attempt_timeout bounds a single HTTP attempt, so one stalled try fails and the SDK retries the operation on a fresh connection while the loop keeps moving. operation_timeout instead bounds the entire operation including all its retries, so to accommodate a 20-second long poll plus retries it must be set generously, meaning a long wait before it fires, and when it does fire it abandons the whole operation rather than letting it recover. Choosing between AWS SDK timeout configs is easier when developers compare real trade-offs on daily.dev."}}]}
```

