[{"data":1,"prerenderedAt":1063},["ShallowReactive",2],{"nav":3,"page-\u002Fasync-background-tasks-observability\u002F":310,"surround-\u002Fasync-background-tasks-observability\u002F":1061},[4,96,212],{"title":5,"path":6,"stem":7,"children":8},"Advanced Pydantic Validation Serialization","\u002Fadvanced-pydantic-validation-serialization","advanced-pydantic-validation-serialization",[9,12,30,42,54,66,90],{"title":10,"path":6,"stem":11},"Advanced Pydantic Validation and Serialization","advanced-pydantic-validation-serialization\u002Findex",{"title":13,"path":14,"stem":15,"children":16},"Custom Validators and Field Constraints in Pydantic","\u002Fadvanced-pydantic-validation-serialization\u002Fcustom-validators-field-constraints","advanced-pydantic-validation-serialization\u002Fcustom-validators-field-constraints\u002Findex",[17,18,24],{"title":13,"path":14,"stem":15},{"title":19,"path":20,"stem":21,"children":22},"Creating Reusable Custom Validators in Pydantic","\u002Fadvanced-pydantic-validation-serialization\u002Fcustom-validators-field-constraints\u002Fcreating-reusable-custom-validators-in-pydantic","advanced-pydantic-validation-serialization\u002Fcustom-validators-field-constraints\u002Fcreating-reusable-custom-validators-in-pydantic\u002Findex",[23],{"title":19,"path":20,"stem":21},{"title":25,"path":26,"stem":27,"children":28},"Pydantic v2 Async Custom Validator: What to Do Instead","\u002Fadvanced-pydantic-validation-serialization\u002Fcustom-validators-field-constraints\u002Fpydantic-v2-async-custom-validator","advanced-pydantic-validation-serialization\u002Fcustom-validators-field-constraints\u002Fpydantic-v2-async-custom-validator\u002Findex",[29],{"title":25,"path":26,"stem":27},{"title":31,"path":32,"stem":33,"children":34},"JSON Schema Customization in Pydantic and FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Fjson-schema-customization","advanced-pydantic-validation-serialization\u002Fjson-schema-customization\u002Findex",[35,36],{"title":31,"path":32,"stem":33},{"title":37,"path":38,"stem":39,"children":40},"Customizing OpenAPI Schema Generation in FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Fjson-schema-customization\u002Fcustomizing-openapi-schema-generation-in-fastapi","advanced-pydantic-validation-serialization\u002Fjson-schema-customization\u002Fcustomizing-openapi-schema-generation-in-fastapi\u002Findex",[41],{"title":37,"path":38,"stem":39},{"title":43,"path":44,"stem":45,"children":46},"Nested Model Serialization in FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Fnested-model-serialization","advanced-pydantic-validation-serialization\u002Fnested-model-serialization\u002Findex",[47,48],{"title":43,"path":44,"stem":45},{"title":49,"path":50,"stem":51,"children":52},"Handling Deeply Nested JSON Models Efficiently","\u002Fadvanced-pydantic-validation-serialization\u002Fnested-model-serialization\u002Fhandling-deeply-nested-json-models-efficiently","advanced-pydantic-validation-serialization\u002Fnested-model-serialization\u002Fhandling-deeply-nested-json-models-efficiently\u002Findex",[53],{"title":49,"path":50,"stem":51},{"title":55,"path":56,"stem":57,"children":58},"Performance Optimization for Pydantic Models in FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Fperformance-optimization-for-models","advanced-pydantic-validation-serialization\u002Fperformance-optimization-for-models\u002Findex",[59,60],{"title":55,"path":56,"stem":57},{"title":61,"path":62,"stem":63,"children":64},"Pydantic Model Serialization Performance in FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Fperformance-optimization-for-models\u002Fpydantic-model-serialization-performance","advanced-pydantic-validation-serialization\u002Fperformance-optimization-for-models\u002Fpydantic-model-serialization-performance\u002Findex",[65],{"title":61,"path":62,"stem":63},{"title":67,"path":68,"stem":69,"children":70},"Pydantic V2 Migration Guide for FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide","advanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002Findex",[71,72,78,84],{"title":67,"path":68,"stem":69},{"title":73,"path":74,"stem":75,"children":76},"Migrate @validator to @field_validator in Pydantic v2","\u002Fadvanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002Fmigrate-validator-to-field-validator","advanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002Fmigrate-validator-to-field-validator\u002Findex",[77],{"title":73,"path":74,"stem":75},{"title":79,"path":80,"stem":81,"children":82},"Migrating from Pydantic v1 to v2 Without Breaking APIs","\u002Fadvanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002Fmigrating-from-pydantic-v1-to-v2-without-breaking-apis","advanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002Fmigrating-from-pydantic-v1-to-v2-without-breaking-apis\u002Findex",[83],{"title":79,"path":80,"stem":81},{"title":85,"path":86,"stem":87,"children":88},"model_config vs class Config in Pydantic v2","\u002Fadvanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002Fmodel-config-vs-class-config","advanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002Fmodel-config-vs-class-config\u002Findex",[89],{"title":85,"path":86,"stem":87},{"title":91,"path":92,"stem":93,"children":94},"Type Hinting and IDE Integration in FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Ftype-hinting-ide-integration","advanced-pydantic-validation-serialization\u002Ftype-hinting-ide-integration\u002Findex",[95],{"title":91,"path":92,"stem":93},{"title":97,"path":98,"stem":99,"children":100},"Async Background Tasks Observability","\u002Fasync-background-tasks-observability","async-background-tasks-observability",[101,104,122,140,158,176,194],{"title":102,"path":98,"stem":103},"Async, Background Tasks, and Observability in FastAPI","async-background-tasks-observability\u002Findex",{"title":105,"path":106,"stem":107,"children":108},"Async Correctness and Concurrency in FastAPI","\u002Fasync-background-tasks-observability\u002Fasync-correctness-concurrency","async-background-tasks-observability\u002Fasync-correctness-concurrency\u002Findex",[109,110,116],{"title":105,"path":106,"stem":107},{"title":111,"path":112,"stem":113,"children":114},"FastAPI async def vs def: Performance and When to Use Each","\u002Fasync-background-tasks-observability\u002Fasync-correctness-concurrency\u002Ffastapi-async-def-vs-def-performance","async-background-tasks-observability\u002Fasync-correctness-concurrency\u002Ffastapi-async-def-vs-def-performance\u002Findex",[115],{"title":111,"path":112,"stem":113},{"title":117,"path":118,"stem":119,"children":120},"Fixing Blocking Calls in Async FastAPI Routes","\u002Fasync-background-tasks-observability\u002Fasync-correctness-concurrency\u002Ffixing-blocking-calls-in-async-routes","async-background-tasks-observability\u002Fasync-correctness-concurrency\u002Ffixing-blocking-calls-in-async-routes\u002Findex",[121],{"title":117,"path":118,"stem":119},{"title":123,"path":124,"stem":125,"children":126},"Async Database Sessions in FastAPI","\u002Fasync-background-tasks-observability\u002Fasync-database-sessions","async-background-tasks-observability\u002Fasync-database-sessions\u002Findex",[127,128,134],{"title":123,"path":124,"stem":125},{"title":129,"path":130,"stem":131,"children":132},"Async SQLAlchemy Session per Request in FastAPI","\u002Fasync-background-tasks-observability\u002Fasync-database-sessions\u002Fasync-sqlalchemy-session-per-request","async-background-tasks-observability\u002Fasync-database-sessions\u002Fasync-sqlalchemy-session-per-request\u002Findex",[133],{"title":129,"path":130,"stem":131},{"title":135,"path":136,"stem":137,"children":138},"Fixing asyncpg Connection Pool Exhaustion in FastAPI","\u002Fasync-background-tasks-observability\u002Fasync-database-sessions\u002Ffixing-asyncpg-pool-exhaustion","async-background-tasks-observability\u002Fasync-database-sessions\u002Ffixing-asyncpg-pool-exhaustion\u002Findex",[139],{"title":135,"path":136,"stem":137},{"title":141,"path":142,"stem":143,"children":144},"Background Task Processing in FastAPI","\u002Fasync-background-tasks-observability\u002Fbackground-task-processing","async-background-tasks-observability\u002Fbackground-task-processing\u002Findex",[145,146,152],{"title":141,"path":142,"stem":143},{"title":147,"path":148,"stem":149,"children":150},"FastAPI BackgroundTasks vs Celery vs ARQ","\u002Fasync-background-tasks-observability\u002Fbackground-task-processing\u002Ffastapi-backgroundtasks-vs-celery-vs-arq","async-background-tasks-observability\u002Fbackground-task-processing\u002Ffastapi-backgroundtasks-vs-celery-vs-arq\u002Findex",[151],{"title":147,"path":148,"stem":149},{"title":153,"path":154,"stem":155,"children":156},"Running ARQ Workers with FastAPI","\u002Fasync-background-tasks-observability\u002Fbackground-task-processing\u002Frunning-arq-workers-with-fastapi","async-background-tasks-observability\u002Fbackground-task-processing\u002Frunning-arq-workers-with-fastapi\u002Findex",[157],{"title":153,"path":154,"stem":155},{"title":159,"path":160,"stem":161,"children":162},"Caching Strategies in FastAPI","\u002Fasync-background-tasks-observability\u002Fcaching-strategies","async-background-tasks-observability\u002Fcaching-strategies\u002Findex",[163,164,170],{"title":159,"path":160,"stem":161},{"title":165,"path":166,"stem":167,"children":168},"Cache Invalidation Patterns in FastAPI","\u002Fasync-background-tasks-observability\u002Fcaching-strategies\u002Fcache-invalidation-patterns-in-fastapi","async-background-tasks-observability\u002Fcaching-strategies\u002Fcache-invalidation-patterns-in-fastapi\u002Findex",[169],{"title":165,"path":166,"stem":167},{"title":171,"path":172,"stem":173,"children":174},"Redis Response Caching in FastAPI","\u002Fasync-background-tasks-observability\u002Fcaching-strategies\u002Fredis-response-caching-in-fastapi","async-background-tasks-observability\u002Fcaching-strategies\u002Fredis-response-caching-in-fastapi\u002Findex",[175],{"title":171,"path":172,"stem":173},{"title":177,"path":178,"stem":179,"children":180},"Observability and Tracing in FastAPI","\u002Fasync-background-tasks-observability\u002Fobservability-and-tracing","async-background-tasks-observability\u002Fobservability-and-tracing\u002Findex",[181,182,188],{"title":177,"path":178,"stem":179},{"title":183,"path":184,"stem":185,"children":186},"Instrumenting FastAPI with OpenTelemetry","\u002Fasync-background-tasks-observability\u002Fobservability-and-tracing\u002Finstrumenting-fastapi-with-opentelemetry","async-background-tasks-observability\u002Fobservability-and-tracing\u002Finstrumenting-fastapi-with-opentelemetry\u002Findex",[187],{"title":183,"path":184,"stem":185},{"title":189,"path":190,"stem":191,"children":192},"Structured JSON Logging with Request IDs in FastAPI","\u002Fasync-background-tasks-observability\u002Fobservability-and-tracing\u002Fstructured-json-logging-with-request-ids","async-background-tasks-observability\u002Fobservability-and-tracing\u002Fstructured-json-logging-with-request-ids\u002Findex",[193],{"title":189,"path":190,"stem":191},{"title":195,"path":196,"stem":197,"children":198},"Rate Limiting and Throttling in FastAPI","\u002Fasync-background-tasks-observability\u002Frate-limiting-throttling","async-background-tasks-observability\u002Frate-limiting-throttling\u002Findex",[199,200,206],{"title":195,"path":196,"stem":197},{"title":201,"path":202,"stem":203,"children":204},"FastAPI Rate Limiting with Redis and SlowAPI","\u002Fasync-background-tasks-observability\u002Frate-limiting-throttling\u002Ffastapi-rate-limiting-with-redis-slowapi","async-background-tasks-observability\u002Frate-limiting-throttling\u002Ffastapi-rate-limiting-with-redis-slowapi\u002Findex",[205],{"title":201,"path":202,"stem":203},{"title":207,"path":208,"stem":209,"children":210},"Per-User Token Bucket Throttling in FastAPI","\u002Fasync-background-tasks-observability\u002Frate-limiting-throttling\u002Fper-user-token-bucket-throttling","async-background-tasks-observability\u002Frate-limiting-throttling\u002Fper-user-token-bucket-throttling\u002Findex",[211],{"title":207,"path":208,"stem":209},{"title":213,"path":214,"stem":215,"children":216},"Core Architecture Routing Patterns","\u002Fcore-architecture-routing-patterns","core-architecture-routing-patterns",[217,220,232,250,268,280,292],{"title":218,"path":214,"stem":219},"FastAPI Core Architecture and Routing Patterns","core-architecture-routing-patterns\u002Findex",{"title":221,"path":222,"stem":223,"children":224},"Application Factory Patterns in FastAPI","\u002Fcore-architecture-routing-patterns\u002Fapplication-factory-patterns","core-architecture-routing-patterns\u002Fapplication-factory-patterns\u002Findex",[225,226],{"title":221,"path":222,"stem":223},{"title":227,"path":228,"stem":229,"children":230},"FastAPI App Factory Pattern for Testing and Deployment","\u002Fcore-architecture-routing-patterns\u002Fapplication-factory-patterns\u002Ffastapi-app-factory-pattern-for-testing-and-deployment","core-architecture-routing-patterns\u002Fapplication-factory-patterns\u002Ffastapi-app-factory-pattern-for-testing-and-deployment\u002Findex",[231],{"title":227,"path":228,"stem":229},{"title":233,"path":234,"stem":235,"children":236},"Configuration Management in FastAPI","\u002Fcore-architecture-routing-patterns\u002Fconfiguration-management","core-architecture-routing-patterns\u002Fconfiguration-management\u002Findex",[237,238,244],{"title":233,"path":234,"stem":235},{"title":239,"path":240,"stem":241,"children":242},"Managing Environment Variables with Pydantic Settings","\u002Fcore-architecture-routing-patterns\u002Fconfiguration-management\u002Fmanaging-environment-variables-with-pydantic-settings","core-architecture-routing-patterns\u002Fconfiguration-management\u002Fmanaging-environment-variables-with-pydantic-settings\u002Findex",[243],{"title":239,"path":240,"stem":241},{"title":245,"path":246,"stem":247,"children":248},"Pydantic Settings vs Dynaconf vs python-decouple","\u002Fcore-architecture-routing-patterns\u002Fconfiguration-management\u002Fpydantic-settings-vs-dynaconf-vs-python-decouple","core-architecture-routing-patterns\u002Fconfiguration-management\u002Fpydantic-settings-vs-dynaconf-vs-python-decouple\u002Findex",[249],{"title":245,"path":246,"stem":247},{"title":251,"path":252,"stem":253,"children":254},"Dependency Injection Strategies in FastAPI","\u002Fcore-architecture-routing-patterns\u002Fdependency-injection-strategies","core-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Findex",[255,256,262],{"title":251,"path":252,"stem":253},{"title":257,"path":258,"stem":259,"children":260},"Best Practices for FastAPI Dependency Injection","\u002Fcore-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Fbest-practices-for-fastapi-dependency-injection","core-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Fbest-practices-for-fastapi-dependency-injection\u002Findex",[261],{"title":257,"path":258,"stem":259},{"title":263,"path":264,"stem":265,"children":266},"Fixing FastAPI Dependency Injection Circular Imports","\u002Fcore-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Ffastapi-dependency-injection-circular-import-fix","core-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Ffastapi-dependency-injection-circular-import-fix\u002Findex",[267],{"title":263,"path":264,"stem":265},{"title":269,"path":270,"stem":271,"children":272},"Error Handling and Global Exceptions in FastAPI","\u002Fcore-architecture-routing-patterns\u002Ferror-handling-global-exceptions","core-architecture-routing-patterns\u002Ferror-handling-global-exceptions\u002Findex",[273,274],{"title":269,"path":270,"stem":271},{"title":275,"path":276,"stem":277,"children":278},"Global Exception Handlers for Consistent API Responses","\u002Fcore-architecture-routing-patterns\u002Ferror-handling-global-exceptions\u002Fglobal-exception-handlers-for-consistent-api-responses","core-architecture-routing-patterns\u002Ferror-handling-global-exceptions\u002Fglobal-exception-handlers-for-consistent-api-responses\u002Findex",[279],{"title":275,"path":276,"stem":277},{"title":281,"path":282,"stem":283,"children":284},"Middleware Implementation in FastAPI","\u002Fcore-architecture-routing-patterns\u002Fmiddleware-implementation","core-architecture-routing-patterns\u002Fmiddleware-implementation\u002Findex",[285,286],{"title":281,"path":282,"stem":283},{"title":287,"path":288,"stem":289,"children":290},"Implementing Custom Middleware for Request Tracing","\u002Fcore-architecture-routing-patterns\u002Fmiddleware-implementation\u002Fimplementing-custom-middleware-for-request-tracing","core-architecture-routing-patterns\u002Fmiddleware-implementation\u002Fimplementing-custom-middleware-for-request-tracing\u002Findex",[291],{"title":287,"path":288,"stem":289},{"title":293,"path":294,"stem":295,"children":296},"Modular Router Organization in FastAPI","\u002Fcore-architecture-routing-patterns\u002Fmodular-router-organization","core-architecture-routing-patterns\u002Fmodular-router-organization\u002Findex",[297,298,304],{"title":293,"path":294,"stem":295},{"title":299,"path":300,"stem":301,"children":302},"APIRouter Prefix vs Sub-Application Mounting in FastAPI","\u002Fcore-architecture-routing-patterns\u002Fmodular-router-organization\u002Fapirouter-prefix-vs-sub-application-mounting","core-architecture-routing-patterns\u002Fmodular-router-organization\u002Fapirouter-prefix-vs-sub-application-mounting\u002Findex",[303],{"title":299,"path":300,"stem":301},{"title":305,"path":306,"stem":307,"children":308},"How to Structure Large FastAPI Projects for Scale","\u002Fcore-architecture-routing-patterns\u002Fmodular-router-organization\u002Fhow-to-structure-large-fastapi-projects-for-scale","core-architecture-routing-patterns\u002Fmodular-router-organization\u002Fhow-to-structure-large-fastapi-projects-for-scale\u002Findex",[309],{"title":305,"path":306,"stem":307},{"id":311,"title":102,"body":312,"description":1034,"extension":1035,"meta":1036,"navigation":579,"path":98,"seo":1059,"stem":103,"__hash__":1060},"content\u002Fasync-background-tasks-observability\u002Findex.md",{"type":313,"value":314,"toc":1023},"minimark",[315,319,323,368,544,549,552,666,671,675,682,773,778,782,785,795,799,802,813,817,820,830,834,837,842,846,955,958,962,971,977,983,987,1019],[316,317,102],"h1",{"id":318},"async-background-tasks-and-observability-in-fastapi",[320,321,322],"p",{},"FastAPI's performance comes from its asynchronous core, but that core is also where production services most often go wrong: a single blocking call stalls every concurrent request, work that should be deferred runs inline, and incidents are impossible to debug without tracing. This section covers the runtime concerns that sit beneath your architecture and data model.",[320,324,325,326,331,332,335,336,340,341,345,346,345,350,345,354,345,358,362,363,367],{},"These are the patterns that decide whether a correct application is also a fast, observable, and resilient one. The section complements ",[327,328,330],"a",{"href":329},"\u002Fcore-architecture-routing-patterns\u002F","Core Architecture and Routing Patterns",", which structures the request path, and ",[327,333,10],{"href":334},"\u002Fadvanced-pydantic-validation-serialization\u002F",", which shapes the data. Start from the ",[327,337,339],{"href":338},"\u002F","home page"," for the full map, and use the focused topics below: ",[327,342,344],{"href":343},"\u002Fasync-background-tasks-observability\u002Fasync-correctness-concurrency\u002F","Async Correctness and Concurrency",", ",[327,347,349],{"href":348},"\u002Fasync-background-tasks-observability\u002Fbackground-task-processing\u002F","Background Task Processing",[327,351,353],{"href":352},"\u002Fasync-background-tasks-observability\u002Fobservability-and-tracing\u002F","Observability and Tracing",[327,355,357],{"href":356},"\u002Fasync-background-tasks-observability\u002Fasync-database-sessions\u002F","Async Database Sessions",[327,359,361],{"href":360},"\u002Fasync-background-tasks-observability\u002Fcaching-strategies\u002F","Caching Strategies",", and ",[327,364,366],{"href":365},"\u002Fasync-background-tasks-observability\u002Frate-limiting-throttling\u002F","Rate Limiting and Throttling",".",[369,370,371,540],"figure",{},[372,373,381,382,381,386,381,390,381,399,381,406,381,411,381,416,381,421,381,425,381,433,381,439,381,443,381,449,381,455,381,459,381,462,381,466,381,470,381,473,381,477,381,481,381,484,381,488,381,492,381,498,381,503,381,507,381,510,381,516,381,520,381,524,381,527,381,531,381,534,381,537],"svg",{"viewBox":374,"role":375,"ariaLabelledBy":376,"xmlns":379,"style":380},"0 0 800 300","img",[377,378],"rt-title","rt-desc","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","width:100%;height:auto;font-family:Inter,system-ui,sans-serif","\n  ",[383,384,385],"title",{"id":377},"The FastAPI production runtime around the event loop",[387,388,389],"desc",{"id":378},"Requests pass a rate limiter into the async event loop. The loop offloads blocking work to a thread pool, enqueues deferred work to a broker and worker, reads and writes an async database pool and a cache, and emits traces, metrics, and logs to a telemetry collector.",[391,392],"rect",{"x":393,"y":394,"width":395,"height":396,"rx":397,"style":398},"20","124","120","52","8","fill:#F9FAFB;stroke:#D1D5DB;stroke-width:1.4px",[400,401,405],"text",{"x":402,"y":403,"style":404},"80","147","fill:#374151;font-size:12px;font-weight:600;text-anchor:middle","Clients",[400,407,410],{"x":402,"y":408,"style":409},"164","fill:#6B7280;font-size:10px;text-anchor:middle","requests",[391,412],{"x":413,"y":394,"width":414,"height":396,"rx":397,"style":415},"166","86","fill:#FFF8EC;stroke:#E0A93B;stroke-width:1.5px",[400,417,420],{"x":418,"y":403,"style":419},"209","fill:#9A6B12;font-size:11px;font-weight:600;text-anchor:middle","rate",[400,422,424],{"x":418,"y":423,"style":419},"162","limiter",[391,426],{"x":427,"y":428,"width":429,"height":430,"rx":431,"style":432},"286","116","180","68","10","fill:#E0F2F1;stroke:#009688;stroke-width:2px",[400,434,438],{"x":435,"y":436,"style":437},"376","144","fill:#00695C;font-size:13px;font-weight:700;text-anchor:middle","Async event loop",[400,440,442],{"x":435,"y":408,"style":441},"fill:#6B7280;font-size:10.5px;text-anchor:middle","await-clean handlers",[391,444],{"x":445,"y":446,"width":429,"height":447,"rx":397,"style":448},"520","24","46","fill:#FFFFFF;stroke:#4DB6AC;stroke-width:1.5px",[400,450,454],{"x":451,"y":452,"style":453},"610","44","fill:#00695C;font-size:11.5px;font-weight:600;text-anchor:middle","Thread \u002F process pool",[400,456,458],{"x":451,"y":457,"style":409},"60","blocking · CPU work",[391,460],{"x":445,"y":461,"width":429,"height":447,"rx":397,"style":448},"90",[400,463,465],{"x":451,"y":464,"style":453},"110","Broker + workers",[400,467,469],{"x":451,"y":468,"style":409},"126","Celery · ARQ",[391,471],{"x":445,"y":472,"width":429,"height":447,"rx":397,"style":448},"156",[400,474,476],{"x":451,"y":475,"style":453},"176","DB pool · cache",[400,478,480],{"x":451,"y":479,"style":409},"192","async sessions · Redis",[391,482],{"x":445,"y":483,"width":429,"height":447,"rx":397,"style":448},"222",[400,485,487],{"x":451,"y":486,"style":453},"242","Telemetry collector",[400,489,491],{"x":451,"y":490,"style":409},"258","traces · metrics · logs",[493,494],"line",{"x1":495,"y1":496,"x2":408,"y2":496,"style":497},"140","150","stroke:#00796B;stroke-width:1.8px",[499,500],"polygon",{"points":501,"style":502},"164,146 172,150 164,154","fill:#00796B",[493,504],{"x1":505,"y1":496,"x2":506,"y2":496,"style":497},"252","284",[499,508],{"points":509,"style":502},"284,146 292,150 284,154",[493,511],{"x1":512,"y1":495,"x2":513,"y2":514,"style":515},"466","518","48","stroke:#4DB6AC;stroke-width:1.5px",[499,517],{"points":518,"style":519},"514,46 520,46 517,54","fill:#4DB6AC",[493,521],{"x1":512,"y1":522,"x2":513,"y2":523,"style":515},"146","112",[499,525],{"points":526,"style":519},"514,109 520,111 515,118",[493,528],{"x1":512,"y1":529,"x2":513,"y2":530,"style":515},"154","178",[499,532],{"points":533,"style":519},"513,173 520,177 512,182",[493,535],{"x1":512,"y1":423,"x2":513,"y2":536,"style":515},"244",[499,538],{"points":539,"style":519},"513,239 519,244 511,248",[541,542,543],"figcaption",{},"The production runtime: a rate limiter guards the loop, blocking and deferred work move off the hot path, shared resources are pooled, and every request emits telemetry.",[545,546,548],"h2",{"id":547},"_1-async-correctness-and-concurrency","1. Async Correctness and Concurrency",[320,550,551],{},"The event loop is single-threaded per worker, so any synchronous call that does not yield blocks every other request on that worker. Correctness here means keeping the hot path await-clean and offloading work that cannot be made async.",[553,554,559],"pre",{"className":555,"code":556,"language":557,"meta":558,"style":558},"language-python shiki shiki-themes github-light","import anyio\n\n\n@app.get(\"\u002Freport\")\nasync def report() -> dict[str, str]:\n    # CPU-bound work offloaded so it cannot stall the loop for other requests.\n    digest = await anyio.to_thread.run_sync(compute_expensive_digest)\n    return {\"digest\": digest}\n","python","",[560,561,562,574,581,586,603,629,636,651],"code",{"__ignoreMap":558},[563,564,566,570],"span",{"class":493,"line":565},1,[563,567,569],{"class":568},"sD7c4","import",[563,571,573],{"class":572},"sgsFI"," anyio\n",[563,575,577],{"class":493,"line":576},2,[563,578,580],{"emptyLinePlaceholder":579},true,"\n",[563,582,584],{"class":493,"line":583},3,[563,585,580],{"emptyLinePlaceholder":579},[563,587,589,593,596,600],{"class":493,"line":588},4,[563,590,592],{"class":591},"s7eDp","@app.get",[563,594,595],{"class":572},"(",[563,597,599],{"class":598},"sYBdl","\"\u002Freport\"",[563,601,602],{"class":572},")\n",[563,604,606,609,612,615,618,622,624,626],{"class":493,"line":605},5,[563,607,608],{"class":568},"async",[563,610,611],{"class":568}," def",[563,613,614],{"class":591}," report",[563,616,617],{"class":572},"() -> dict[",[563,619,621],{"class":620},"sYu0t","str",[563,623,345],{"class":572},[563,625,621],{"class":620},[563,627,628],{"class":572},"]:\n",[563,630,632],{"class":493,"line":631},6,[563,633,635],{"class":634},"sAwPA","    # CPU-bound work offloaded so it cannot stall the loop for other requests.\n",[563,637,639,642,645,648],{"class":493,"line":638},7,[563,640,641],{"class":572},"    digest ",[563,643,644],{"class":568},"=",[563,646,647],{"class":568}," await",[563,649,650],{"class":572}," anyio.to_thread.run_sync(compute_expensive_digest)\n",[563,652,654,657,660,663],{"class":493,"line":653},8,[563,655,656],{"class":568},"    return",[563,658,659],{"class":572}," {",[563,661,662],{"class":598},"\"digest\"",[563,664,665],{"class":572},": digest}\n",[320,667,668,669,367],{},"Why this matters at scale: one blocking call in a popular endpoint degrades latency for the entire worker, not just that request. The diagnosis and remedies are in ",[327,670,344],{"href":343},[545,672,674],{"id":673},"_2-background-task-processing","2. Background Task Processing",[320,676,677,678,681],{},"Work the client does not need in order to get a response should not run in the request. FastAPI's ",[560,679,680],{},"BackgroundTasks"," handles short fire-and-forget jobs; durable, retryable work belongs in a queue such as Celery or ARQ.",[553,683,685],{"className":555,"code":684,"language":557,"meta":558,"style":558},"from fastapi import BackgroundTasks\n\n\n@app.post(\"\u002Fsignup\")\nasync def signup(email: str, tasks: BackgroundTasks) -> dict[str, str]:\n    # Respond immediately; deliver the welcome email after the response is sent.\n    tasks.add_task(send_welcome_email, email)\n    return {\"status\": \"accepted\"}\n",[560,686,687,700,704,708,720,745,750,755],{"__ignoreMap":558},[563,688,689,692,695,697],{"class":493,"line":565},[563,690,691],{"class":568},"from",[563,693,694],{"class":572}," fastapi ",[563,696,569],{"class":568},[563,698,699],{"class":572}," BackgroundTasks\n",[563,701,702],{"class":493,"line":576},[563,703,580],{"emptyLinePlaceholder":579},[563,705,706],{"class":493,"line":583},[563,707,580],{"emptyLinePlaceholder":579},[563,709,710,713,715,718],{"class":493,"line":588},[563,711,712],{"class":591},"@app.post",[563,714,595],{"class":572},[563,716,717],{"class":598},"\"\u002Fsignup\"",[563,719,602],{"class":572},[563,721,722,724,726,729,732,734,737,739,741,743],{"class":493,"line":605},[563,723,608],{"class":568},[563,725,611],{"class":568},[563,727,728],{"class":591}," signup",[563,730,731],{"class":572},"(email: ",[563,733,621],{"class":620},[563,735,736],{"class":572},", tasks: BackgroundTasks) -> dict[",[563,738,621],{"class":620},[563,740,345],{"class":572},[563,742,621],{"class":620},[563,744,628],{"class":572},[563,746,747],{"class":493,"line":631},[563,748,749],{"class":634},"    # Respond immediately; deliver the welcome email after the response is sent.\n",[563,751,752],{"class":493,"line":638},[563,753,754],{"class":572},"    tasks.add_task(send_welcome_email, email)\n",[563,756,757,759,761,764,767,770],{"class":493,"line":653},[563,758,656],{"class":568},[563,760,659],{"class":572},[563,762,763],{"class":598},"\"status\"",[563,765,766],{"class":572},": ",[563,768,769],{"class":598},"\"accepted\"",[563,771,772],{"class":572},"}\n",[320,774,775,776,367],{},"Why this matters at scale: inlining slow side effects inflates response times and couples request success to third-party availability. The decision between in-process and queued work is in ",[327,777,349],{"href":348},[545,779,781],{"id":780},"_3-observability-and-tracing","3. Observability and Tracing",[320,783,784],{},"When something breaks at 2am, observability is the difference between a query and a guess. Correlation IDs, distributed traces, metrics, and structured logs must be wired into the request lifecycle.",[320,786,787,788,792,793,367],{},"Why this matters at scale: across many services, a single slow request is invisible without a trace that spans them. The instrumentation approach builds on the correlation ID from ",[327,789,791],{"href":790},"\u002Fcore-architecture-routing-patterns\u002Fmiddleware-implementation\u002F","middleware"," and is detailed in ",[327,794,353],{"href":352},[545,796,798],{"id":797},"_4-async-database-sessions","4. Async Database Sessions",[320,800,801],{},"The database is where async correctness is won or lost, because a synchronous driver is the most common loop-blocking culprit. Async sessions, drawn per request from a shared pool, keep database I\u002FO off the loop.",[320,803,804,805,807,808,812],{},"Why this matters at scale: pool sizing and session scope determine how many concurrent requests you can serve before queries queue. The patterns are in ",[327,806,357],{"href":356},", and they extend the ",[327,809,811],{"href":810},"\u002Fcore-architecture-routing-patterns\u002Fdependency-injection-strategies\u002F","dependency injection"," session pattern.",[545,814,816],{"id":815},"_5-caching-strategies","5. Caching Strategies",[320,818,819],{},"The fastest query is the one you never make. Caching hot, rarely-changing data in Redis cuts latency and database load, at the cost of invalidation complexity.",[320,821,822,823,825,826,367],{},"Why this matters at scale: a cache turns a database-bound endpoint into a memory-bound one, but a stale cache serves wrong answers. The trade-offs are in ",[327,824,361],{"href":360},", which pairs with ",[327,827,829],{"href":828},"\u002Fadvanced-pydantic-validation-serialization\u002Fperformance-optimization-for-models\u002F","serialization performance",[545,831,833],{"id":832},"_6-rate-limiting-and-throttling","6. Rate Limiting and Throttling",[320,835,836],{},"A public API needs to protect itself. Rate limiting bounds how much any one client can consume, defending shared resources and keeping one heavy user from degrading everyone else.",[320,838,839,840,367],{},"Why this matters at scale: without limits, a single misbehaving client or a retry storm can exhaust your pools. The algorithms and storage choices are in ",[327,841,366],{"href":365},[545,843,845],{"id":844},"cross-cutting-trade-offs","Cross-Cutting Trade-offs",[847,848,849,868],"table",{},[850,851,852],"thead",{},[853,854,855,859,862,865],"tr",{},[856,857,858],"th",{},"Concern",[856,860,861],{},"Simple choice",[856,863,864],{},"Scales better as",[856,866,867],{},"Primary cost",[869,870,871,886,899,913,927,941],"tbody",{},[853,872,873,877,880,883],{},[874,875,876],"td",{},"Blocking work",[874,878,879],{},"Run inline",[874,881,882],{},"Offload to a pool",[874,884,885],{},"Manage the pool",[853,887,888,891,893,896],{},[874,889,890],{},"Deferred work",[874,892,680],{},[874,894,895],{},"Celery \u002F ARQ queue",[874,897,898],{},"Run a broker + workers",[853,900,901,904,907,910],{},[874,902,903],{},"Tracing",[874,905,906],{},"Logs only",[874,908,909],{},"Distributed traces",[874,911,912],{},"Instrumentation upkeep",[853,914,915,918,921,924],{},[874,916,917],{},"DB access",[874,919,920],{},"Sync driver",[874,922,923],{},"Async sessions + pool",[874,925,926],{},"Async everywhere",[853,928,929,932,935,938],{},[874,930,931],{},"Hot reads",[874,933,934],{},"Hit the DB",[874,936,937],{},"Cache + invalidation",[874,939,940],{},"Staleness management",[853,942,943,946,949,952],{},[874,944,945],{},"Abuse control",[874,947,948],{},"None",[874,950,951],{},"Rate limiter",[874,953,954],{},"Shared limiter store",[320,956,957],{},"The pattern: each row trades a small amount of operational complexity for a large gain in latency, resilience, or debuggability under real load.",[545,959,961],{"id":960},"common-production-pitfalls","Common Production Pitfalls",[320,963,964,968,969,367],{},[965,966,967],"strong",{},"A sync call hidden in an async handler."," The hardest blocking bugs are indirect — a library that does blocking I\u002FO internally. Audit dependencies and offload, as in ",[327,970,344],{"href":343},[320,972,973,976],{},[965,974,975],{},"Background work that loses request context."," A task scheduled after the response runs outside the request's context, so the correlation ID is gone unless you pass it in explicitly.",[320,978,979,982],{},[965,980,981],{},"An unbounded pool or queue."," A database pool or task queue with no ceiling converts a traffic spike into a resource-exhaustion outage. Size them and add rate limiting upstream.",[545,984,986],{"id":985},"related-reading","Related Reading",[988,989,990,1009],"ul",{},[991,992,993,996,997,345,999,345,1001,345,1003,345,1005,362,1007,367],"li",{},[965,994,995],{},"Within this section:"," ",[327,998,344],{"href":343},[327,1000,349],{"href":348},[327,1002,353],{"href":352},[327,1004,357],{"href":356},[327,1006,361],{"href":360},[327,1008,366],{"href":365},[991,1010,1011,996,1014,1016,1017,367],{},[965,1012,1013],{},"Sibling sections:",[327,1015,330],{"href":329}," and ",[327,1018,10],{"href":334},[1020,1021,1022],"style",{},"html pre.shiki code .sD7c4, html code.shiki .sD7c4{--shiki-default:#D73A49}html pre.shiki code .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}html pre.shiki code .s7eDp, html code.shiki .s7eDp{--shiki-default:#6F42C1}html pre.shiki code .sYBdl, html code.shiki .sYBdl{--shiki-default:#032F62}html pre.shiki code .sYu0t, html code.shiki .sYu0t{--shiki-default:#005CC5}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}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);}",{"title":558,"searchDepth":576,"depth":576,"links":1024},[1025,1026,1027,1028,1029,1030,1031,1032,1033],{"id":547,"depth":576,"text":548},{"id":673,"depth":576,"text":674},{"id":780,"depth":576,"text":781},{"id":797,"depth":576,"text":798},{"id":815,"depth":576,"text":816},{"id":832,"depth":576,"text":833},{"id":844,"depth":576,"text":845},{"id":960,"depth":576,"text":961},{"id":985,"depth":576,"text":986},"Production runtime patterns for FastAPI: async correctness, offloading blocking work, background task processing with Celery and ARQ, OpenTelemetry tracing, async DB sessions, caching, and rate limiting.","md",{"slug":99,"type":1037,"breadcrumb":1038,"datePublished":1044,"dateModified":1045,"faq":1046},"pillar",[1039,1041],{"label":1040,"path":338},"Home",{"label":1042,"path":1043},"Async, Background Tasks & Observability","\u002Fasync-background-tasks-observability\u002F","2026-02-10","2026-06-18",[1047,1050,1053,1056],{"q":1048,"a":1049},"What is the single most common async mistake in FastAPI?","Calling blocking code inside an async def route. A synchronous database driver, a requests call, or a CPU-bound loop blocks the event loop and stalls every other request the worker is handling. The fix is to use async libraries on the hot path and offload unavoidable blocking work to a thread or process pool.",{"q":1051,"a":1052},"When should work move to a background task instead of running in the request?","Move work out of the request whenever the client does not need the result to respond — sending email, generating a report, syncing a third-party system. Short fire-and-forget work can use FastAPI's BackgroundTasks; durable, retryable, or long-running work belongs in a real queue such as Celery or ARQ.",{"q":1054,"a":1055},"Why is observability treated as an architectural concern rather than an add-on?","Because you cannot bolt it on after an incident. Correlation IDs, traces, metrics, and structured logs have to be threaded through the request lifecycle from the start. When they are, debugging a production issue is a query; when they are not, it is guesswork across disconnected logs.",{"q":1057,"a":1058},"How do async database sessions differ from synchronous ones?","An async session is created per request from a shared async engine and pool, and every database call is awaited so it yields the event loop instead of blocking it. The session is provided through a yield dependency so it is committed or rolled back and always closed, and the pool is sized to your concurrency.",{"title":102,"description":1034},"sHDUGBZnDGyM5B6AE9ewj-9EA0mExMiGul3TBrwtGx8",[1062,1062],null,1781809863153]