Repository navigation
Document proxy and SDK timeout budgets for worker long polling #267
Description
The original all-eight-locale long-poll guide is delivered. The focused published PHP 3.4 deadline update is also live and verified in all eight locales; historical 3.2 and Nginx/Python observations remain unchanged.
Self-hosted worker long polls can be cut off by a shorter proxy/load-balancer idle timeout even when the runtime and worker are healthy. Operators need a clear relationship between the server wait, SDK HTTP timeout and every intermediary's timeout, rather than a timeout number copied from another engine.
Validated source:
- Docs main
8b1ced52295511a4a676e32517ebf44a349c528f: Deployment describes a default 30-second/max-60-second long-poll window and readiness/load-balancer rules, but does not give an end-to-end idle/read-timeout budget example. Task matching describes polling/wake tuning separately. - Python SDK main
101c591f45de3e0b03dc9d87b64a1254ddfe10e5: client.py clamps the requested server poll wait to 60 seconds and gives positive polls at least five seconds of HTTP timeout grace. Requested values and HTTP budgets are therefore related but not identical. - PHP Server main
1682e1de2160cfa50ed9456bab3ae48fc08f6fb8: LongPoller owns the server wait/deadline using the configured poll timeout.
Priority P2, deployment reliability guidance. No proxy failure has been reproduced against our published runtime, and this is not a gRPC compression feature request.
Acceptance:
- Distinguish server poll duration, client connect/read/total budgets, proxy idle/read limits and shutdown/caller deadlines. Explain which limits must allow a legitimate quiet poll to finish and the margin needed for its response.
- Give one concrete example checked against a named published SDK/server baseline. Do not prescribe Temporal's 70-second default or assume all first-party SDKs have identical timeout arithmetic.
- Explain what an intermediary disconnect looks like compared with empty-poll completion, runtime unavailability and namespace admission rejection. Retrying a connection is not proof the original proxy configuration was healthy.
- Cover shared API ingress and every proxy hop. Keep provider-specific settings conditional and verified; a layer-number recommendation alone does not establish correct timeouts.
- Include an isolated proxy fixture where an idle limit shorter than the legitimate server wait interrupts a poll, then a sufficient budget permits it. Do not extend an existing query/caller authority deadline to make that fixture pass.
Published-runtime qualification is complete; receipt 6360233554 records exact images, requests, unchanged caller bounds and proxy outcomes. Existing documentation issue metadata contained no equivalent long-poll proxy-budget task.
Delivery status
Delivered in PR #367, merge c47580ebd0f0f609e3ae16160e5298f9511f797e. Exact-head all-locale qualification, artifact deployment and Pages publication passed. Sixteen live routes and all eight configuration-row links were exercised in Chromium; English and font-qualified Japanese/Chinese 390px light/dark layouts passed. The documentation requirements are complete. Separate SDK product limitations remain linked and are not claimed fixed.
Activity
rmcdaniel commentedon Oct 19, 2026
For the diagnostic section, pair transport errors with actual continued polling/completion and persistent failure context. A sporadic disconnect is not itself a reason to restart the worker. Keep HTTP SDK-specific retry/timeout behavior separate from Temporal Rust Core/NativeConnection gRPC keepalive settings; an HTTP/2 keepalive flag is not a portable fix for every proxy idle limit. This is already within the issue's intermediary-disconnect versus empty-poll/unavailable-response scope.
rmcdaniel commentedon Oct 19, 2026
Source facts relevant to the timeout-budget guidance (Server
4e0f6458, SDK main as of October 19):timeout_seconds(up to the protocol maximum of 60) overridesDW_WORKER_POLL_TIMEOUT.LongPollerfalls back to the server setting only when the request omits it, and every SDK sends one. The server config reference describes the variable as the time "the server holds a poll open", so lowering it does not shorten SDK polls.Worker(poll_timeout=35.0), Rust 30 seconds, PHP shorter. An intermediary with a 30-second idle limit would cut every quiet Python poll..recover_transient_outages(true)is set, as its README documents.rmcdaniel commentedon Oct 20, 2026
Product review:
Keep as deployment guidance: proxy/server/client timeout budgets are real configuration choices, and the requested relationship does not establish a new polling primitive. Verify a real quiet poll through a bounded proxy fixture without extending caller/query authority. SDK-Python #167 owns the separate blank transport-error/cancellation-diagnostic defect; correct guidance must not stand in for that fix.
rmcdaniel commentedon Oct 23, 2026
Taking the deployment timeout-budget guide and its isolated proxy qualification. The recorded product review stands: this is deployment guidance, while SDK-Python #167 owns its separate diagnostic defect.
Next: run the same published SDK/Server quiet poll through an intermediary whose upstream read timeout is shorter than the poll, then through a sufficient timeout, without changing SDK poll duration or caller authority. Document the verified baseline, every hop, response diagnostics and all eight languages.
rmcdaniel commentedon Oct 23, 2026
Published proxy qualification passes. Draft guidance and the Server fallback-wait correction are in #367. This remains deployment guidance; it does not deliver the separate Python diagnostic fix.
Exact tuple: normally installed Python SDK 2.9.0, wheel SHA-256
1e7547e895485dc8f670bd1b9cc34184b135f249db8da98b16b250bfc6002f73; published PHP Server 2.11.0, image indexsha256:b29157eb2cf844916debbbb3c01b3257672e0dece778a9c6fa539043a3038f02; Nginx 1.30.5, image indexsha256:0985e772fb9f729e6fa0980da05fca5d9c468e870eed43071545afa9d2e27d94. Python 3.12 / amd64 / SQLite; no source overlays.Both independent empty-queue polls use
timeout_seconds: 3, HTTPX connect/read/write/pool = 8 seconds, and the same 10-second outer caller bound. HTTP retries allow one attempt to expose the first response. Only Nginx's upstream read timeout changes. The Server fallback remainsDW_WORKER_POLL_TIMEOUT=1in both cells, demonstrating that it does not cap an explicit SDK wait. No query or business workflow is admitted; no existing authority or deadline is extended.ServerError, HTTP 504, 1.009 seconds. Proxy independently logs an upstream timeout while reading the response header.task: null,poll_status: empty.The request hook records actual wire waits and HTTP phase budgets. This is a local functional test, not a production-capacity, TLS, managed-ingress, Cloud, native Server or other-SDK qualification. API and proxy both stopped exit 0 / no OOM; their task containers and network were removed.
The first fixture expected the wrong label (
timeoutinstead of the runtime'sempty) and remains a failed fixture assertion, not a product failure. Fresh confirming cells keep the same poll and caller budgets. Installed Python source can synthesizepoll_status: timeoutafter HTTP timeout retries; that value alone does not prove a runtime empty response traversed the proxy. The guide explains this distinction.Semantics were checked against the Nginx upstream read-timeout reference and HTTPX timeout reference.
Actual requests, outcomes and standalone fixture sources
Run the pinned Server in an isolated Docker network with alias
api, bootstrap its own SQLite database, and setDW_AUTH_DRIVER=noneonly for this fixture. Run pinned Nginx in that network with aliasproxyand this configuration. No host ports are needed. Mount the installed Python package and fixture in a Python 3.12 container on the same network; runtimeout 30 python -u /task/probe.py. The fixture uses the installed Worker's registration path, then the published Client poll API. It writes the outcome to its task mount. Cleanup affects only task resources.[ { "response": null, "exception": "ServerError", "status": 504, "message": "server returned 504: '<html>\\r\\n<head><title>504 Gateway Time-out</title></head>\\r\\n<body>\\r\\n<center><h1>504 Gateway Time-out</h1></center>\\r\\n<hr><center>nginx/1.30.5</center>\\r\\n</body>\\r\\n</html>\\r\\n'", "case": "short", "elapsed": 1.0092643380630761, "requests": [ { "body": { "worker_id": "website267-short-2", "task_queue": "website267-short-2", "poll_request_id": "wf-poll-9cd7cf4d5aef4b268119e4d60af0bbe7", "timeout_seconds": 3 }, "timeout": { "connect": 8.0, "read": 8.0, "write": 8.0, "pool": 8.0 } } ], "caller_bound_seconds": 10 }, { "response": { "task": null, "poll_status": "empty", "protocol_version": "1.20" }, "exception": null, "case": "sufficient", "elapsed": 3.320714259054512, "requests": [ { "body": { "worker_id": "website267-sufficient-2", "task_queue": "website267-sufficient-2", "poll_request_id": "wf-poll-b8f1f3301ca149c78b8ef1525effc20c", "timeout_seconds": 3 }, "timeout": { "connect": 8.0, "read": 8.0, "write": 8.0, "pool": 8.0 } } ], "caller_bound_seconds": 10 } ]nginx.conf (SHA-256
bc54891f1373310af61ed380922bbfa4c2c405696a006d3729be8b941a9f2907)probe.py (SHA-256
f51f54fbf6ddcb29bc605460ef893d43118d1c1d4857b3ea74efa9a7ed712187)Next: translate both changed guides in all seven other languages, record reviewed source hashes, finish build/CI, inspect rendered routes and deploy.
rmcdaniel commentedon Oct 23, 2026
Delivered in PR #367, merge
c47580ebd0f0f609e3ae16160e5298f9511f797e.Exact-head qualification, artifact deployment and actual Pages publication pass. The deployment and configuration guides are current in all eight languages, with matching examples and source hashes.
All sixteen canonical public routes return HTTP 200 with the new anchors or configuration-row link. Chromium followed the actual
DW_WORKER_POLL_TIMEOUTrow link into the localized budget section in every language and checked the two-row proxy example, PHP #203 limitation link and canonical/alternate metadata. English, Japanese and Chinese pass 390px light/dark reflow. The CJK visual checks use installed Japanese/Chinese fonts; missing-font screenshots from the initial browser environment were not accepted as visual evidence.The published runtime qualification proves the short proxy cutoff and sufficient-budget empty poll without changing the SDK poll duration or caller bound. The guide covers client phases versus total deadlines, every proxy hop on shared API ingress, separate shutdown/query authority, and empty responses versus disconnects, runtime failures and admission refusals. It preserves the separate PHP timeout limitation and does not claim a Python diagnostic product fix.
Read the worker long-poll budget guide. Task runtimes, networks and raw databases are retired. The merged remote branch is absent from GitHub.
rmcdaniel commentedon Oct 23, 2026
The focused PHP timeout follow-through is live in all eight deployment guides, through PR #390, merge
6929717489e4cc1bc411a46634b4d42d9ae184cc.Final exact-head all-locale CI, artifact publication, and the separate actual Pages deployment pass. All checks pass; Sonar reports zero new issues. The SDK maintainer reviewed the source; both precision findings are fixed in every locale: finite values of at least 0.001 seconds, and typed timeout reasons scoped to SDK-owned requests.
Live checks pass for eight canonical routes, all nine alternate-language URLs per page, section TOCs, the preserved 3.2.0 baseline and new 3.4.0 deadline/error/configuration tokens, and both HTTP-setup/installed-receipt links in every locale. The English/Japanese/Chinese 390px light/dark screenshots specifically target the new paragraph; it is readable with CJK fonts and no document overflow.
The live timeout-budget guide now distinguishes the 60-second SDK-owned control-request default, configured deadline, injected transports, mutation ambiguity and separate worker/payload/workflow/caller clocks. Published SDK acceptance is the runtime authority; Packagist source/dist and the live setup page were independently checked. No duplicate runtime test, tuple promotion or consumer-image adoption is claimed. Historical 3.2.0 and Nginx/Python observations remain unchanged. Source worktree and remote branch are retired; the separate consumer follow-through stays with its owner.