[{"data":1,"prerenderedAt":1447},["ShallowReactive",2],{"page-\u002Fasync-engines-dialects-and-connection-pooling\u002Fconfiguring-async-engines-and-connection-pools\u002F":3},{"id":4,"title":5,"body":6,"description":16,"extension":1441,"meta":1442,"navigation":152,"path":1443,"seo":1444,"stem":1445,"__hash__":1446},"content\u002Fasync-engines-dialects-and-connection-pooling\u002Fconfiguring-async-engines-and-connection-pools\u002Findex.md","Configuring Async Engines and Connection Pools",{"type":7,"value":8,"toc":1401},"minimark",[9,13,17,22,31,61,65,68,72,93,377,381,391,408,412,419,423,435,630,634,643,654,658,677,681,698,702,708,711,743,747,750,754,764,996,1000,1007,1018,1025,1036,1040,1043,1047,1051,1054,1058,1069,1073,1081,1239,1243,1324,1328,1347,1365,1379,1397],[10,11,5],"h1",{"id":12},"configuring-async-engines-and-connection-pools",[14,15,16],"p",{},"Configuring async engines and connection pools in SQLAlchemy 2.0 requires a deliberate approach to resource allocation, event loop boundaries, and driver-specific tuning. Unlike synchronous architectures where thread pools absorb I\u002FO latency, async engines rely on cooperative concurrency. Misconfigured pools quickly become bottlenecks, causing queue starvation, connection leaks, or greenlet context violations. This guide details production-ready initialization patterns, concurrency calibration, and lifecycle management for high-throughput async applications.",[18,19,21],"h2",{"id":20},"async-engine-initialization-and-dialect-routing","Async Engine Initialization and Dialect Routing",[23,24,26,30],"h3",{"id":25},"create_async_engine-parameter-mapping",[27,28,29],"code",{},"create_async_engine"," parameter mapping",[14,32,33,34,36,37,40,41,44,45,48,49,52,53,56,57,60],{},"The ",[27,35,29],{}," factory serves as the entry point for all async database interactions. It wraps a synchronous ",[27,38,39],{},"Engine"," with an async-compatible facade, routing execution through the appropriate async DBAPI. Core parameters like ",[27,42,43],{},"pool_size",", ",[27,46,47],{},"pool_timeout",", and ",[27,50,51],{},"echo"," map directly to the underlying ",[27,54,55],{},"QueuePool"," implementation, but must be tuned for non-blocking I\u002FO. In SQLAlchemy 2.0, ",[27,58,59],{},"future=True"," is the default and should never be overridden.",[23,62,64],{"id":63},"async-dialect-string-resolution","Async dialect string resolution",[14,66,67],{},"Dialect resolution occurs at engine instantiation. The URL prefix dictates the underlying async driver and its event loop integration strategy. SQLAlchemy validates the dialect string against installed async adapters, raising immediate errors if the required package is missing or incompatible with the current Python runtime.",[23,69,71],{"id":70},"event-loop-compatibility-checks","Event loop compatibility checks",[14,73,74,75,78,79,82,83,86,87,92],{},"SQLAlchemy performs implicit event loop validation when the first connection is requested. Drivers like ",[27,76,77],{},"asyncpg"," and ",[27,80,81],{},"psycopg"," require the running event loop to be active and unblocked. Attempting to initialize an engine in a synchronous context or mixing event loop policies will trigger ",[27,84,85],{},"RuntimeError"," exceptions. For foundational connection lifecycle management, consult the architectural overview in ",[88,89,91],"a",{"href":90},"\u002Fasync-engines-dialects-and-connection-pooling\u002F","Async Engines, Dialects, and Connection Pooling"," before applying concurrency-specific overrides.",[94,95,100],"pre",{"className":96,"code":97,"language":98,"meta":99,"style":99},"language-python shiki shiki-themes github-light github-dark","from typing import Any\nfrom sqlalchemy.ext.asyncio import create_async_engine, AsyncSession\nfrom sqlalchemy.orm import sessionmaker\n\n# Production-ready base configuration with explicit typing\nDATABASE_URL = \"postgresql+asyncpg:\u002F\u002Fuser:pass@host:5432\u002Fappdb\"\n\nengine = create_async_engine(\n DATABASE_URL,\n pool_size=20,\n max_overflow=10,\n pool_timeout=30.0,\n pool_recycle=3600,\n pool_pre_ping=True,\n echo=False,\n # future=True is default in 2.0; explicit for clarity\n future=True,\n)\n\n# Explicit session factory bound to the async engine\nAsyncSessionFactory = sessionmaker(\n bind=engine,\n class_=AsyncSession,\n expire_on_commit=False,\n autoflush=False,\n)\n","python","",[27,101,102,121,134,147,154,161,175,180,192,201,215,228,241,254,267,280,286,298,304,309,315,326,337,348,360,372],{"__ignoreMap":99},[103,104,107,111,115,118],"span",{"class":105,"line":106},"line",1,[103,108,110],{"class":109},"szBVR","from",[103,112,114],{"class":113},"sVt8B"," typing ",[103,116,117],{"class":109},"import",[103,119,120],{"class":113}," Any\n",[103,122,124,126,129,131],{"class":105,"line":123},2,[103,125,110],{"class":109},[103,127,128],{"class":113}," sqlalchemy.ext.asyncio ",[103,130,117],{"class":109},[103,132,133],{"class":113}," create_async_engine, AsyncSession\n",[103,135,137,139,142,144],{"class":105,"line":136},3,[103,138,110],{"class":109},[103,140,141],{"class":113}," sqlalchemy.orm ",[103,143,117],{"class":109},[103,145,146],{"class":113}," sessionmaker\n",[103,148,150],{"class":105,"line":149},4,[103,151,153],{"emptyLinePlaceholder":152},true,"\n",[103,155,157],{"class":105,"line":156},5,[103,158,160],{"class":159},"sJ8bj","# Production-ready base configuration with explicit typing\n",[103,162,164,168,171],{"class":105,"line":163},6,[103,165,167],{"class":166},"sj4cs","DATABASE_URL",[103,169,170],{"class":109}," =",[103,172,174],{"class":173},"sZZnC"," \"postgresql+asyncpg:\u002F\u002Fuser:pass@host:5432\u002Fappdb\"\n",[103,176,178],{"class":105,"line":177},7,[103,179,153],{"emptyLinePlaceholder":152},[103,181,183,186,189],{"class":105,"line":182},8,[103,184,185],{"class":113},"engine ",[103,187,188],{"class":109},"=",[103,190,191],{"class":113}," create_async_engine(\n",[103,193,195,198],{"class":105,"line":194},9,[103,196,197],{"class":166}," DATABASE_URL",[103,199,200],{"class":113},",\n",[103,202,204,208,210,213],{"class":105,"line":203},10,[103,205,207],{"class":206},"s4XuR"," pool_size",[103,209,188],{"class":109},[103,211,212],{"class":166},"20",[103,214,200],{"class":113},[103,216,218,221,223,226],{"class":105,"line":217},11,[103,219,220],{"class":206}," max_overflow",[103,222,188],{"class":109},[103,224,225],{"class":166},"10",[103,227,200],{"class":113},[103,229,231,234,236,239],{"class":105,"line":230},12,[103,232,233],{"class":206}," pool_timeout",[103,235,188],{"class":109},[103,237,238],{"class":166},"30.0",[103,240,200],{"class":113},[103,242,244,247,249,252],{"class":105,"line":243},13,[103,245,246],{"class":206}," pool_recycle",[103,248,188],{"class":109},[103,250,251],{"class":166},"3600",[103,253,200],{"class":113},[103,255,257,260,262,265],{"class":105,"line":256},14,[103,258,259],{"class":206}," pool_pre_ping",[103,261,188],{"class":109},[103,263,264],{"class":166},"True",[103,266,200],{"class":113},[103,268,270,273,275,278],{"class":105,"line":269},15,[103,271,272],{"class":206}," echo",[103,274,188],{"class":109},[103,276,277],{"class":166},"False",[103,279,200],{"class":113},[103,281,283],{"class":105,"line":282},16,[103,284,285],{"class":159}," # future=True is default in 2.0; explicit for clarity\n",[103,287,289,292,294,296],{"class":105,"line":288},17,[103,290,291],{"class":206}," future",[103,293,188],{"class":109},[103,295,264],{"class":166},[103,297,200],{"class":113},[103,299,301],{"class":105,"line":300},18,[103,302,303],{"class":113},")\n",[103,305,307],{"class":105,"line":306},19,[103,308,153],{"emptyLinePlaceholder":152},[103,310,312],{"class":105,"line":311},20,[103,313,314],{"class":159},"# Explicit session factory bound to the async engine\n",[103,316,318,321,323],{"class":105,"line":317},21,[103,319,320],{"class":113},"AsyncSessionFactory ",[103,322,188],{"class":109},[103,324,325],{"class":113}," sessionmaker(\n",[103,327,329,332,334],{"class":105,"line":328},22,[103,330,331],{"class":206}," bind",[103,333,188],{"class":109},[103,335,336],{"class":113},"engine,\n",[103,338,340,343,345],{"class":105,"line":339},23,[103,341,342],{"class":206}," class_",[103,344,188],{"class":109},[103,346,347],{"class":113},"AsyncSession,\n",[103,349,351,354,356,358],{"class":105,"line":350},24,[103,352,353],{"class":206}," expire_on_commit",[103,355,188],{"class":109},[103,357,277],{"class":166},[103,359,200],{"class":113},[103,361,363,366,368,370],{"class":105,"line":362},25,[103,364,365],{"class":206}," autoflush",[103,367,188],{"class":109},[103,369,277],{"class":166},[103,371,200],{"class":113},[103,373,375],{"class":105,"line":374},26,[103,376,303],{"class":113},[18,378,380],{"id":379},"driver-selection-and-async-dialect-configuration","Driver Selection and Async Dialect Configuration",[23,382,384,386,387,390],{"id":383},"asyncpg-vs-psycopg3-dialect-strings",[27,385,77],{}," vs ",[27,388,389],{},"psycopg3"," dialect strings",[14,392,393,394,397,398,400,401,404,405,407],{},"The dialect string determines the async DBAPI implementation. ",[27,395,396],{},"postgresql+asyncpg:\u002F\u002F"," routes to the ",[27,399,77],{}," library, while ",[27,402,403],{},"postgresql+psycopg:\u002F\u002F"," targets the modern ",[27,406,81],{}," (v3) async driver. Both support native async I\u002FO, but differ in type coercion, prepared statement caching, and connection initialization overhead.",[23,409,411],{"id":410},"native-async-vs-greenlet-fallback","Native async vs greenlet fallback",[14,413,414,415,418],{},"SQLAlchemy 2.0 eliminates the need for ",[27,416,417],{},"greenlet"," when using native async drivers. If a synchronous DBAPI is accidentally specified in an async context, SQLAlchemy will attempt to spawn greenlets, introducing unpredictable latency and context-switching overhead. Always verify the dialect prefix matches an async-capable adapter.",[23,420,422],{"id":421},"connection-parameter-passthrough","Connection parameter passthrough",[14,424,425,426,429,430,434],{},"Driver-specific socket, TLS, and caching parameters are passed via ",[27,427,428],{},"connect_args",". These bypass SQLAlchemy's pool abstraction and are applied directly to the underlying connection factory. Evaluate performance trade-offs and type coercion behaviors detailed in ",[88,431,433],{"href":432},"\u002Fasync-engines-dialects-and-connection-pooling\u002Fchoosing-between-asyncpg-and-psycopg-async-drivers\u002F","Choosing Between asyncpg and psycopg Async Drivers"," to align with schema complexity.",[94,436,438],{"className":96,"code":437,"language":98,"meta":99,"style":99},"from typing import TypedDict\n\nclass AsyncpgConnectArgs(TypedDict, total=False):\n command_timeout: int\n statement_cache_size: int\n max_cached_statement_lifetime: int\n ssl: bool\n\nconnect_args: AsyncpgConnectArgs = {\n \"command_timeout\": 10,\n \"statement_cache_size\": 100,\n \"max_cached_statement_lifetime\": 1800,\n \"ssl\": True,\n}\n\nengine = create_async_engine(\n DATABASE_URL,\n connect_args=connect_args,\n pool_size=20,\n max_overflow=10,\n)\n",[27,439,440,451,455,482,490,497,504,512,516,526,538,550,562,573,578,582,590,596,606,616,626],{"__ignoreMap":99},[103,441,442,444,446,448],{"class":105,"line":106},[103,443,110],{"class":109},[103,445,114],{"class":113},[103,447,117],{"class":109},[103,449,450],{"class":113}," TypedDict\n",[103,452,453],{"class":105,"line":123},[103,454,153],{"emptyLinePlaceholder":152},[103,456,457,460,464,467,470,472,475,477,479],{"class":105,"line":136},[103,458,459],{"class":109},"class",[103,461,463],{"class":462},"sScJk"," AsyncpgConnectArgs",[103,465,466],{"class":113},"(",[103,468,469],{"class":462},"TypedDict",[103,471,44],{"class":113},[103,473,474],{"class":206},"total",[103,476,188],{"class":109},[103,478,277],{"class":166},[103,480,481],{"class":113},"):\n",[103,483,484,487],{"class":105,"line":149},[103,485,486],{"class":113}," command_timeout: ",[103,488,489],{"class":166},"int\n",[103,491,492,495],{"class":105,"line":156},[103,493,494],{"class":113}," statement_cache_size: ",[103,496,489],{"class":166},[103,498,499,502],{"class":105,"line":163},[103,500,501],{"class":113}," max_cached_statement_lifetime: ",[103,503,489],{"class":166},[103,505,506,509],{"class":105,"line":177},[103,507,508],{"class":113}," ssl: ",[103,510,511],{"class":166},"bool\n",[103,513,514],{"class":105,"line":182},[103,515,153],{"emptyLinePlaceholder":152},[103,517,518,521,523],{"class":105,"line":194},[103,519,520],{"class":113},"connect_args: AsyncpgConnectArgs ",[103,522,188],{"class":109},[103,524,525],{"class":113}," {\n",[103,527,528,531,534,536],{"class":105,"line":203},[103,529,530],{"class":173}," \"command_timeout\"",[103,532,533],{"class":113},": ",[103,535,225],{"class":166},[103,537,200],{"class":113},[103,539,540,543,545,548],{"class":105,"line":217},[103,541,542],{"class":173}," \"statement_cache_size\"",[103,544,533],{"class":113},[103,546,547],{"class":166},"100",[103,549,200],{"class":113},[103,551,552,555,557,560],{"class":105,"line":230},[103,553,554],{"class":173}," \"max_cached_statement_lifetime\"",[103,556,533],{"class":113},[103,558,559],{"class":166},"1800",[103,561,200],{"class":113},[103,563,564,567,569,571],{"class":105,"line":243},[103,565,566],{"class":173}," \"ssl\"",[103,568,533],{"class":113},[103,570,264],{"class":166},[103,572,200],{"class":113},[103,574,575],{"class":105,"line":256},[103,576,577],{"class":113},"}\n",[103,579,580],{"class":105,"line":269},[103,581,153],{"emptyLinePlaceholder":152},[103,583,584,586,588],{"class":105,"line":282},[103,585,185],{"class":113},[103,587,188],{"class":109},[103,589,191],{"class":113},[103,591,592,594],{"class":105,"line":288},[103,593,197],{"class":166},[103,595,200],{"class":113},[103,597,598,601,603],{"class":105,"line":300},[103,599,600],{"class":206}," connect_args",[103,602,188],{"class":109},[103,604,605],{"class":113},"connect_args,\n",[103,607,608,610,612,614],{"class":105,"line":306},[103,609,207],{"class":206},[103,611,188],{"class":109},[103,613,212],{"class":166},[103,615,200],{"class":113},[103,617,618,620,622,624],{"class":105,"line":311},[103,619,220],{"class":206},[103,621,188],{"class":109},[103,623,225],{"class":166},[103,625,200],{"class":113},[103,627,628],{"class":105,"line":317},[103,629,303],{"class":113},[18,631,633],{"id":632},"pool-sizing-and-concurrency-calibration","Pool Sizing and Concurrency Calibration",[23,635,637,386,639,642],{"id":636},"pool_size-vs-max_overflow-calculation",[27,638,43],{},[27,640,641],{},"max_overflow"," calculation",[14,644,645,647,648,650,651,653],{},[27,646,43],{}," defines the baseline number of persistent connections maintained by the pool. ",[27,649,641],{}," allows temporary expansion during traffic spikes. Exceeding ",[27,652,43],{}," triggers overflow connections, which are discarded after use and do not persist in the pool.",[23,655,657],{"id":656},"cpu-to-io-wait-ratio-modeling","CPU-to-I\u002FO wait ratio modeling",[14,659,660,661,664,665,668,669,672,673,676],{},"Optimal pool sizing depends on the application's I\u002FO wait characteristics. For database-bound async workloads, a common heuristic is:\n",[27,662,663],{},"pool_size ≈ (CPU_Cores × I\u002FO_Wait_Factor) + Spindle_Count","\nWhere ",[27,666,667],{},"I\u002FO_Wait_Factor"," typically ranges from ",[27,670,671],{},"2.0"," to ",[27,674,675],{},"4.0",". Async applications benefit from higher ratios than threaded apps because connection checkout is non-blocking.",[23,678,680],{"id":679},"queue-overflow-and-starvation-prevention","Queue overflow and starvation prevention",[14,682,683,684,686,687,689,690,692,693,697],{},"When all ",[27,685,43],{}," + ",[27,688,641],{}," connections are in use, new requests block until ",[27,691,47],{}," expires. Calculate optimal pool boundaries using thread count and expected concurrent request volume. Apply sizing formulas and benchmark thresholds from ",[88,694,696],{"href":695},"\u002Fasync-engines-dialects-and-connection-pooling\u002Fconfiguring-async-engines-and-connection-pools\u002Fsetting-up-asyncpg-connection-pool-size-for-high-concurrency\u002F","Setting Up asyncpg Connection Pool Size for High Concurrency"," to prevent queue bottlenecks.",[18,699,701],{"id":700},"timeout-thresholds-and-retry-topology","Timeout Thresholds and Retry Topology",[23,703,705,707],{"id":704},"connect_args-timeout-mapping",[27,706,428],{}," timeout mapping",[14,709,710],{},"Timeouts operate at three distinct layers:",[712,713,714,725,734],"ol",{},[715,716,717,724],"li",{},[718,719,720,721,723],"strong",{},"Pool Timeout (",[27,722,47],{},")",": Maximum wait time for an available connection from the pool.",[715,726,727,733],{},[718,728,729,730,723],{},"Connection Timeout (",[27,731,732],{},"connect_timeout",": TCP handshake and authentication duration.",[715,735,736,742],{},[718,737,738,739,723],{},"Statement Timeout (",[27,740,741],{},"command_timeout",": Maximum execution time per query.",[23,744,746],{"id":745},"exponential-backoff-implementation","Exponential backoff implementation",[14,748,749],{},"Transient network failures or database failovers require resilient retry logic. Implement exponential backoff with jitter at the application layer rather than relying on driver-level retries, which lack transaction awareness.",[23,751,753],{"id":752},"transient-error-classification","Transient error classification",[14,755,756,757,44,760,763],{},"Classify errors as retryable (e.g., ",[27,758,759],{},"ConnectionResetError",[27,761,762],{},"asyncpg.exceptions.ConnectionDoesNotExistError",") or fatal (e.g., syntax errors, constraint violations). Integrate resilient retry logic and circuit-breaker patterns as prescribed in Implementing Connection Timeouts and Retries in asyncpg for distributed workloads.",[94,765,767],{"className":96,"code":766,"language":98,"meta":99,"style":99},"import asyncio\nfrom typing import TypeVar, Callable, Awaitable\nfrom sqlalchemy.exc import OperationalError\n\nT = TypeVar(\"T\")\n\nasync def execute_with_retry(\n func: Callable[..., Awaitable[T]],\n max_retries: int = 3,\n base_delay: float = 0.5,\n) -> T:\n for attempt in range(max_retries + 1):\n try:\n return await func()\n except (OperationalError, ConnectionError) as e:\n if attempt == max_retries:\n raise\n delay = base_delay * (2 ** attempt)\n await asyncio.sleep(delay)\n",[27,768,769,776,787,799,803,818,822,836,847,862,877,882,907,915,926,946,959,964,989],{"__ignoreMap":99},[103,770,771,773],{"class":105,"line":106},[103,772,117],{"class":109},[103,774,775],{"class":113}," asyncio\n",[103,777,778,780,782,784],{"class":105,"line":123},[103,779,110],{"class":109},[103,781,114],{"class":113},[103,783,117],{"class":109},[103,785,786],{"class":113}," TypeVar, Callable, Awaitable\n",[103,788,789,791,794,796],{"class":105,"line":136},[103,790,110],{"class":109},[103,792,793],{"class":113}," sqlalchemy.exc ",[103,795,117],{"class":109},[103,797,798],{"class":113}," OperationalError\n",[103,800,801],{"class":105,"line":149},[103,802,153],{"emptyLinePlaceholder":152},[103,804,805,808,810,813,816],{"class":105,"line":156},[103,806,807],{"class":113},"T ",[103,809,188],{"class":109},[103,811,812],{"class":113}," TypeVar(",[103,814,815],{"class":173},"\"T\"",[103,817,303],{"class":113},[103,819,820],{"class":105,"line":163},[103,821,153],{"emptyLinePlaceholder":152},[103,823,824,827,830,833],{"class":105,"line":177},[103,825,826],{"class":109},"async",[103,828,829],{"class":109}," def",[103,831,832],{"class":462}," execute_with_retry",[103,834,835],{"class":113},"(\n",[103,837,838,841,844],{"class":105,"line":182},[103,839,840],{"class":113}," func: Callable[",[103,842,843],{"class":166},"...",[103,845,846],{"class":113},", Awaitable[T]],\n",[103,848,849,852,855,857,860],{"class":105,"line":194},[103,850,851],{"class":113}," max_retries: ",[103,853,854],{"class":166},"int",[103,856,170],{"class":109},[103,858,859],{"class":166}," 3",[103,861,200],{"class":113},[103,863,864,867,870,872,875],{"class":105,"line":203},[103,865,866],{"class":113}," base_delay: ",[103,868,869],{"class":166},"float",[103,871,170],{"class":109},[103,873,874],{"class":166}," 0.5",[103,876,200],{"class":113},[103,878,879],{"class":105,"line":217},[103,880,881],{"class":113},") -> T:\n",[103,883,884,887,890,893,896,899,902,905],{"class":105,"line":230},[103,885,886],{"class":109}," for",[103,888,889],{"class":113}," attempt ",[103,891,892],{"class":109},"in",[103,894,895],{"class":166}," range",[103,897,898],{"class":113},"(max_retries ",[103,900,901],{"class":109},"+",[103,903,904],{"class":166}," 1",[103,906,481],{"class":113},[103,908,909,912],{"class":105,"line":243},[103,910,911],{"class":109}," try",[103,913,914],{"class":113},":\n",[103,916,917,920,923],{"class":105,"line":256},[103,918,919],{"class":109}," return",[103,921,922],{"class":109}," await",[103,924,925],{"class":113}," func()\n",[103,927,928,931,934,937,940,943],{"class":105,"line":269},[103,929,930],{"class":109}," except",[103,932,933],{"class":113}," (OperationalError, ",[103,935,936],{"class":166},"ConnectionError",[103,938,939],{"class":113},") ",[103,941,942],{"class":109},"as",[103,944,945],{"class":113}," e:\n",[103,947,948,951,953,956],{"class":105,"line":282},[103,949,950],{"class":109}," if",[103,952,889],{"class":113},[103,954,955],{"class":109},"==",[103,957,958],{"class":113}," max_retries:\n",[103,960,961],{"class":105,"line":288},[103,962,963],{"class":109}," raise\n",[103,965,966,969,971,974,977,980,983,986],{"class":105,"line":300},[103,967,968],{"class":113}," delay ",[103,970,188],{"class":109},[103,972,973],{"class":113}," base_delay ",[103,975,976],{"class":109},"*",[103,978,979],{"class":113}," (",[103,981,982],{"class":166},"2",[103,984,985],{"class":109}," **",[103,987,988],{"class":113}," attempt)\n",[103,990,991,993],{"class":105,"line":306},[103,992,922],{"class":109},[103,994,995],{"class":113}," asyncio.sleep(delay)\n",[18,997,999],{"id":998},"pool-recycling-and-stale-connection-mitigation","Pool Recycling and Stale Connection Mitigation",[23,1001,1003,1006],{"id":1002},"pool_recycle-interval-tuning",[27,1004,1005],{},"pool_recycle"," interval tuning",[14,1008,1009,1011,1012,1014,1015,1017],{},[27,1010,1005],{}," forces connections to be closed and replaced after a specified duration. Cloud providers (AWS RDS, GCP Cloud SQL, Azure Database) often terminate idle connections after 15–60 minutes. Setting ",[27,1013,1005],{}," slightly below the provider's idle timeout prevents ",[27,1016,759],{}," on checkout.",[23,1019,1021,1024],{"id":1020},"pool_pre_ping-health-checks",[27,1022,1023],{},"pool_pre_ping"," health checks",[14,1026,1027,1028,1031,1032,1035],{},"When ",[27,1029,1030],{},"pool_pre_ping=True",", SQLAlchemy issues a lightweight ",[27,1033,1034],{},"SELECT 1"," before handing a connection to the caller. This adds ~1–2ms latency per checkout but guarantees connection validity. Disable only in strictly controlled, low-latency internal networks.",[23,1037,1039],{"id":1038},"connection-state-validation","Connection state validation",[14,1041,1042],{},"Prevent database-side connection drops and TCP half-open states by tuning recycle intervals. Implement lifecycle validation strategies covered in Optimizing Connection Pool Recycling for Long-Running Workers for background task processors.",[18,1044,1046],{"id":1045},"framework-integration-and-event-loop-binding","Framework Integration and Event Loop Binding",[23,1048,1050],{"id":1049},"dependency-injection-scoping","Dependency injection scoping",[14,1052,1053],{},"Async engines should be instantiated once at application startup and injected into request handlers via dependency injection. Re-initializing engines per request bypasses connection pooling and exhausts database resources.",[23,1055,1057],{"id":1056},"async-session-lifecycle-hooks","Async session lifecycle hooks",[14,1059,1060,1061,1064,1065,1068],{},"Sessions must be scoped to the request lifecycle. Use context managers or framework-specific middleware to guarantee ",[27,1062,1063],{},"commit","\u002F",[27,1066,1067],{},"rollback"," execution and automatic connection release back to the pool.",[23,1070,1072],{"id":1071},"graceful-shutdown-and-pool-disposal","Graceful shutdown and pool disposal",[14,1074,1075,1076,1080],{},"Failing to cleanly dispose of the engine leaves background tasks and TCP sockets dangling. Align engine configuration with framework-specific lifecycle management as demonstrated in ",[88,1077,1079],{"href":1078},"\u002Fasync-engines-dialects-and-connection-pooling\u002Fintegrating-sqlalchemy-async-with-fastapi-and-starlette\u002F","Integrating SQLAlchemy Async with FastAPI and Starlette"," to avoid event loop blocking.",[94,1082,1084],{"className":96,"code":1083,"language":98,"meta":99,"style":99},"from contextlib import asynccontextmanager\nfrom sqlalchemy.ext.asyncio import AsyncEngine, AsyncSession\n\n@asynccontextmanager\nasync def get_db_session(engine: AsyncEngine) -> AsyncSession:\n async with AsyncSession(engine) as session:\n try:\n yield session\n await session.commit()\n except Exception:\n await session.rollback()\n raise\n finally:\n await session.close()\n\nasync def shutdown_engine(engine: AsyncEngine) -> None:\n \"\"\"Ensures all background connection tasks are cancelled and TCP sockets \n are cleanly closed before process exit.\"\"\"\n await engine.dispose()\n",[27,1085,1086,1098,1109,1113,1118,1130,1146,1152,1160,1167,1176,1183,1187,1194,1201,1205,1222,1227,1232],{"__ignoreMap":99},[103,1087,1088,1090,1093,1095],{"class":105,"line":106},[103,1089,110],{"class":109},[103,1091,1092],{"class":113}," contextlib ",[103,1094,117],{"class":109},[103,1096,1097],{"class":113}," asynccontextmanager\n",[103,1099,1100,1102,1104,1106],{"class":105,"line":123},[103,1101,110],{"class":109},[103,1103,128],{"class":113},[103,1105,117],{"class":109},[103,1107,1108],{"class":113}," AsyncEngine, AsyncSession\n",[103,1110,1111],{"class":105,"line":136},[103,1112,153],{"emptyLinePlaceholder":152},[103,1114,1115],{"class":105,"line":149},[103,1116,1117],{"class":462},"@asynccontextmanager\n",[103,1119,1120,1122,1124,1127],{"class":105,"line":156},[103,1121,826],{"class":109},[103,1123,829],{"class":109},[103,1125,1126],{"class":462}," get_db_session",[103,1128,1129],{"class":113},"(engine: AsyncEngine) -> AsyncSession:\n",[103,1131,1132,1135,1138,1141,1143],{"class":105,"line":163},[103,1133,1134],{"class":109}," async",[103,1136,1137],{"class":109}," with",[103,1139,1140],{"class":113}," AsyncSession(engine) ",[103,1142,942],{"class":109},[103,1144,1145],{"class":113}," session:\n",[103,1147,1148,1150],{"class":105,"line":177},[103,1149,911],{"class":109},[103,1151,914],{"class":113},[103,1153,1154,1157],{"class":105,"line":182},[103,1155,1156],{"class":109}," yield",[103,1158,1159],{"class":113}," session\n",[103,1161,1162,1164],{"class":105,"line":194},[103,1163,922],{"class":109},[103,1165,1166],{"class":113}," session.commit()\n",[103,1168,1169,1171,1174],{"class":105,"line":203},[103,1170,930],{"class":109},[103,1172,1173],{"class":166}," Exception",[103,1175,914],{"class":113},[103,1177,1178,1180],{"class":105,"line":217},[103,1179,922],{"class":109},[103,1181,1182],{"class":113}," session.rollback()\n",[103,1184,1185],{"class":105,"line":230},[103,1186,963],{"class":109},[103,1188,1189,1192],{"class":105,"line":243},[103,1190,1191],{"class":109}," finally",[103,1193,914],{"class":113},[103,1195,1196,1198],{"class":105,"line":256},[103,1197,922],{"class":109},[103,1199,1200],{"class":113}," session.close()\n",[103,1202,1203],{"class":105,"line":269},[103,1204,153],{"emptyLinePlaceholder":152},[103,1206,1207,1209,1211,1214,1217,1220],{"class":105,"line":282},[103,1208,826],{"class":109},[103,1210,829],{"class":109},[103,1212,1213],{"class":462}," shutdown_engine",[103,1215,1216],{"class":113},"(engine: AsyncEngine) -> ",[103,1218,1219],{"class":166},"None",[103,1221,914],{"class":113},[103,1223,1224],{"class":105,"line":288},[103,1225,1226],{"class":173}," \"\"\"Ensures all background connection tasks are cancelled and TCP sockets \n",[103,1228,1229],{"class":105,"line":300},[103,1230,1231],{"class":173}," are cleanly closed before process exit.\"\"\"\n",[103,1233,1234,1236],{"class":105,"line":306},[103,1235,922],{"class":109},[103,1237,1238],{"class":113}," engine.dispose()\n",[18,1240,1242],{"id":1241},"production-pitfalls","Production Pitfalls",[1244,1245,1246,1264,1276,1294,1309],"ul",{},[715,1247,1248,1254,1255,1257,1258,1260,1261,1263],{},[718,1249,1250,1251],{},"Exceeding ",[27,1252,1253],{},"max_connections",": Setting ",[27,1256,43],{}," higher than the database's configured ",[27,1259,1253],{}," causes immediate connection rejection. Always reserve 10–20% of ",[27,1262,1253],{}," for administrative and replication tasks.",[715,1265,1266,1272,1273,1275],{},[718,1267,1268,1269,1271],{},"Missing ",[27,1270,1023],{}," in cloud environments",": Omitting health checks in cloud-hosted databases with aggressive idle termination policies results in intermittent ",[27,1274,759],{}," spikes during low-traffic periods.",[715,1277,1278,1281,1282,1285,1286,1289,1290,1293],{},[718,1279,1280],{},"Synchronous ORM calls in async handlers",": Using ",[27,1283,1284],{},"Session"," instead of ",[27,1287,1288],{},"AsyncSession"," or omitting ",[27,1291,1292],{},"await"," on execution methods triggers greenlet context errors. Maintain strict async\u002Fawait boundaries.",[715,1295,1296,1301,1302,1304,1305,1308],{},[718,1297,1298,1299],{},"Overly aggressive ",[27,1300,1005],{},": Configuring ",[27,1303,1005],{}," too low (e.g., ",[27,1306,1307],{},"\u003C 300s",") forces unnecessary TCP handshakes, increasing latency and CPU overhead.",[715,1310,1311,1317,1318,1320,1321,1323],{},[718,1312,1313,1314],{},"Neglecting ",[27,1315,1316],{},"engine.dispose()",": Failing to await ",[27,1319,1316],{}," during application teardown results in lingering ",[27,1322,77],{}," tasks, event loop warnings, and potential file descriptor leaks during container scaling.",[18,1325,1327],{"id":1326},"frequently-asked-questions","Frequently Asked Questions",[14,1329,1330,1336,1337,1339,1340,1342,1343,1346],{},[718,1331,1332,1333,1335],{},"How do I calculate the optimal ",[27,1334,43],{}," for an async SQLAlchemy engine?","\nBase ",[27,1338,43],{}," on the number of CPU cores multiplied by the expected I\u002FO wait factor (typically 2–4x for DB-bound async workloads). Add ",[27,1341,641],{}," to absorb traffic spikes without queuing indefinitely. Monitor ",[27,1344,1345],{},"pool_overflow_count"," metrics to adjust dynamically.",[14,1348,1349,1358,1359,1361,1362,1364],{},[718,1350,1351,1352,1354,1355,1357],{},"When should I use ",[27,1353,1023],{}," versus ",[27,1356,1005],{},"?","\nUse ",[27,1360,1023],{}," to validate connection health before each checkout, ideal for unstable networks or unpredictable cloud routing. Use ",[27,1363,1005],{}," to proactively close and replace connections after a set duration, preventing database-side idle timeouts. They are complementary, not mutually exclusive.",[14,1366,1367,1375,1376,1378],{},[718,1368,1369,1370,78,1372,1374],{},"Can I mix ",[27,1371,77],{},[27,1373,389],{}," in the same application?","\nYes, by instantiating separate async engines with distinct dialect strings. However, sharing connection pools or ",[27,1377,1288],{}," instances across different drivers is unsupported and will cause dialect routing conflicts and type coercion errors.",[14,1380,1381,1384,1385,78,1387,1389,1390,1392,1393,1396],{},[718,1382,1383],{},"Why does my async engine throw a 'greenlet' error in FastAPI?","\nThis occurs when synchronous ORM operations or legacy DBAPI calls are executed within an async context. Ensure all queries use ",[27,1386,1288],{},[27,1388,1292],{}," execution methods, and configure the driver for native async mode. Verify that no synchronous ",[27,1391,1284],{}," or ",[27,1394,1395],{},"text()"," calls leak into async request handlers.",[1398,1399,1400],"style",{},"html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}",{"title":99,"searchDepth":123,"depth":123,"links":1402},[1403,1409,1415,1421,1427,1434,1439,1440],{"id":20,"depth":123,"text":21,"children":1404},[1405,1407,1408],{"id":25,"depth":136,"text":1406},"create_async_engine parameter mapping",{"id":63,"depth":136,"text":64},{"id":70,"depth":136,"text":71},{"id":379,"depth":123,"text":380,"children":1410},[1411,1413,1414],{"id":383,"depth":136,"text":1412},"asyncpg vs psycopg3 dialect strings",{"id":410,"depth":136,"text":411},{"id":421,"depth":136,"text":422},{"id":632,"depth":123,"text":633,"children":1416},[1417,1419,1420],{"id":636,"depth":136,"text":1418},"pool_size vs max_overflow calculation",{"id":656,"depth":136,"text":657},{"id":679,"depth":136,"text":680},{"id":700,"depth":123,"text":701,"children":1422},[1423,1425,1426],{"id":704,"depth":136,"text":1424},"connect_args timeout mapping",{"id":745,"depth":136,"text":746},{"id":752,"depth":136,"text":753},{"id":998,"depth":123,"text":999,"children":1428},[1429,1431,1433],{"id":1002,"depth":136,"text":1430},"pool_recycle interval tuning",{"id":1020,"depth":136,"text":1432},"pool_pre_ping health checks",{"id":1038,"depth":136,"text":1039},{"id":1045,"depth":123,"text":1046,"children":1435},[1436,1437,1438],{"id":1049,"depth":136,"text":1050},{"id":1056,"depth":136,"text":1057},{"id":1071,"depth":136,"text":1072},{"id":1241,"depth":123,"text":1242},{"id":1326,"depth":123,"text":1327},"md",{},"\u002Fasync-engines-dialects-and-connection-pooling\u002Fconfiguring-async-engines-and-connection-pools",{"title":5,"description":16},"async-engines-dialects-and-connection-pooling\u002Fconfiguring-async-engines-and-connection-pools\u002Findex","fDwG0PwxRH8_hro-EIVe0ichYNV0IRL1-DYGLQSDO9A",1778149144399]