بلاگز / FastAPI BackgroundTasks بمقابلہ Celery: کب کیا استعمال کریں

FastAPI BackgroundTasks بمقابلہ Celery: کب کیا استعمال کریں

شائع ہوا
27 اگست، 2026
مصنف
Faizan Nadeem
ٹیگز
FastAPI Python Celery Backend Development
فیکٹری کی اسمبلی لائن پر صنعتی conveyor belt کے ساتھ چلتے ہوئے دھاتی پرزے
Unsplash پر Salvador Escalante کی تصویر

BackgroundTasks دیکھنے میں ایسا لگتا ہے جیسے یہ وہی مسئلہ حل کرتا ہے جو Celery کرتی ہے — یعنی response جانے کے بعد کچھ کام چلانا، بغیر اس کے کہ صارف کو اس کے لیے انتظار کرنا پڑے۔ یہ FastAPI میں built-in ہے، کسی اضافی infrastructure کی ضرورت نہیں ہوتی، اور اسے استعمال کرنے کا code صرف تین لائنوں کا ہے۔ یہی سادگی بالکل وہ وجہ ہے جس کی بنا پر teams اسے confirmation emails بھیجنے، report generation job شروع کرنے، یا audit log entry لکھنے کے لیے فوراً استعمال کرتی ہیں۔ اور یہ اس وقت تک کام بھی کرتا ہے جب تک request کے دوران deploy نہ آ جائے، یا process OOM-kill نہ ہو جائے، یا pod autoscaler کسی instance کو terminate کرنے کا فیصلہ نہ کر لے — اور پھر وہ task جو “background” میں تھا، سادہ طور پر کبھی ہوتا ہی نہیں، نہ کوئی error، نہ retry، نہ یہ کوئی record کہ اسے کبھی چلنا بھی تھا۔

یہ failure mode BackgroundTasks کا bug نہیں ہے۔ یہ BackgroundTasks کا بالکل وہی کام ہے جس کے لیے اسے design کیا گیا تھا — response کے بعد، اسی process کے اندر، بغیر کسی persistence layer کے coroutine چلانا۔ اصل غلطی یہ ہے کہ اسے ایسے کام کے لیے استعمال کیا جائے جسے وہ guarantees درکار ہوں جو صرف ایک حقیقی task queue دے سکتی ہے۔ یہ post واضح کرے گی کہ BackgroundTasks حقیقت میں کیا ہے، کن مخصوص حالات میں یہ خاموشی سے کام drop کر دیتا ہے، Celery اسے درست کرنے کے لیے کیا اضافہ کرتی ہے، اور دونوں میں انتخاب کے لیے ایک عملی framework کیا ہے تاکہ آپ صرف اسی پر default نہ کریں جسے پہلے setup کیا تھا۔

آپ یہ سیکھیں گے:

  • BackgroundTasks اندرونی طور پر اصل میں کیا کرتا ہے، اور یہ request کے اسی process میں کیوں چلتا ہے
  • وہ مخصوص failure scenarios — deploys، crashes، autoscaling — جن میں BackgroundTasks خاموشی سے کام کھو دیتا ہے
  • Celery ساختی طور پر کیا اضافہ کرتی ہے: broker، persistence، retries، اور آزاد worker processes
  • durability requirements، retry کی ضرورت، اور متوقع task duration کی بنیاد پر ایک decision framework
  • دونوں کو کیسے ملایا جائے — واقعی fire-and-forget کام کے لیے BackgroundTasks، اور ہر اس چیز کے لیے Celery جسے guarantee چاہیے
  • دونوں کے working code examples، جن میں Celery retry policy اور ایک FastAPI endpoint شامل ہے جو اسی کو dispatch کرتا ہے

فہرستِ مضامین

  1. بنیادی باتیں
  2. BackgroundTasks اصل میں کیسے کام کرتا ہے
  3. BackgroundTasks کہاں خاموشی سے کام drop کرتا ہے
  4. Celery کیا اضافہ کرتی ہے
  5. فیصلہ سازی کا فریم ورک
  6. Hybrid patterns
  7. Code examples
  8. Celery کے ہلکے alternatives
  9. عام غلطیاں
  10. Production best practices

بنیادی باتیں

دو مختلف مسائل حل کرنے والے دو مختلف tools

BackgroundTasks Starlette کی ایک feature ہے جسے FastAPI براہِ راست expose کرتی ہے: ایسا طریقہ جس سے کسی function کو HTTP response بھیجے جانے کے بعد، اسی worker process کے اندر schedule کیا جا سکے جس نے request handle کی تھی۔ Celery ایک distributed task queue ہے: ایک الگ system جس کے اپنے worker processes ہوتے ہیں، آپ کی app اور ان workers کے درمیان ایک message broker (عام طور پر Redis یا RabbitMQ) ہوتا ہے، اور ایک results/state backend ہوتا ہے جو app process restart ہونے کے بعد بھی برقرار رہتا ہے۔

سطحی مماثلت — “اسے بعد میں چلاؤ، response کو block مت کرو” — ایک بہت بڑے ساختی فرق کو چھپا دیتی ہے: BackgroundTasks کے پاس سرے سے کوئی persistence layer نہیں ہوتی۔ اگر task schedule کرنے والا process task مکمل ہونے سے پہلے مر جائے، تو task بھی ختم ہو جاتا ہے۔ Celery کا broker task کو enqueue ہوتے ہی persist کر دیتا ہے، اس سے آزاد کہ جب worker اسے اٹھائے تو API process ابھی چل بھی رہا ہو یا نہیں۔

یہ فرق اکثر کیوں نظرانداز ہو جاتا ہے

زیادہ تر tutorials BackgroundTasks کو واقعی fire-and-forget مثالوں کے ساتھ متعارف کراتی ہیں — logging، cache warm — جہاں کبھی کبھار task کھو جانا نقصان دہ نہیں ہوتا۔ پھر teams یہی pattern ان چیزوں کے لیے بھی استعمال کرنے لگتی ہیں جن کا کھو جانا بے ضرر نہیں: password reset email بھیجنا، payment charge کرنا، ایسا document generate کرنا جس کا صارف انتظار کر رہا ہو۔ دونوں cases میں API ایک جیسی لگتی ہے۔ failure کا نتیجہ ایک جیسا نہیں ہوتا۔

BackgroundTasks اصل میں کیسے کام کرتا ہے

ایک BackgroundTasks object route میں inject کیا جاتا ہے، اس پر functions register کیے جاتے ہیں، اور FastAPI response بھیجے جانے کے بعد انہیں چلاتی ہے — مگر پھر بھی اسی async event loop کے اندر، اسی worker process میں:

from fastapi import FastAPI, BackgroundTasks

app = FastAPI()

def send_confirmation_email(email: str):
    # runs after the response has already gone out
    email_client.send(email, "Thanks for signing up")

@app.post("/signup")
async def signup(email: str, background_tasks: BackgroundTasks):
    create_user(email)
    background_tasks.add_task(send_confirmation_email, email)
    return {"status": "created"}

صارف کو create_user ختم ہوتے ہی response مل جاتا ہے — وہ send_confirmation_email کا بالکل انتظار نہیں کرتا۔ یہی پوری value proposition ہے، اور یہ واقعی مفید بھی ہے۔ لیکن غور کریں کہ کیا نہیں ہو رہا: یہاں کوئی queue نہیں، کوئی broker نہیں، کوئی الگ worker نہیں، اور نہ ہی کوئی ایسی چیز جو track کرے کہ send_confirmation_email حقیقت میں کبھی مکمل بھی ہوا یا نہیں۔ یہ اسی process lifecycle کے اندر ایک scheduled coroutine call ہے جس نے request trigger کی — asyncio.create_task کے زیادہ قریب، اور کسی job queue سے بہت دور، بس ergonomics کچھ بہتر ہیں۔

اگر send_confirmation_email خود synchronous اور blocking ہو، تو یہ بھی اسی threadpool-or-event-loop constraints کے اندر چلتا ہے جن کی وضاحت Why Your FastAPI Endpoint Blocks the Event Loop میں کی گئی ہے — ایک سست background task پورے process کی throughput کو خراب کر سکتا ہے اگر اسے loop کے ساتھ cooperate کرنے کے لیے نہ لکھا گیا ہو۔ add_task کے ساتھ register کیا گیا synchronous function Starlette کے threadpool میں بالکل ویسے ہی چلتا ہے جیسے کوئی def route چلتا، جبکہ اسی طرح register کیا گیا async def function براہِ راست event loop پر چلتا ہے — اس لیے ایسا background task جو await کیے بغیر block کرے، صرف دوسرے background کام نہیں بلکہ in-flight requests کو بھی stall کر سکتا ہے، اور یہی بات آسانی سے نظر سے اوجھل رہتی ہے کیونکہ پہلی نظر میں task request/response cycle سے الگ دکھائی دیتا ہے۔

Exception handling کو غلط سمجھنا بھی اتنا ہی آسان ہے۔ اگر registered task exception raise کرے، تو FastAPI response کو crash نہیں کرتی — وہ تو پہلے ہی جا چکا ہوتا ہے — مگر default طور پر exception صرف اسی صورت نظر آتی ہے جب آپ کی logging setup خاص طور پر background tasks سے آنے والی unhandled exceptions کو capture کرتی ہو؛ route کے گرد ایک سادہ try/except اسے کبھی نہیں دیکھتا، کیونکہ جب تک task چلتا ہے، route function پہلے ہی return کر چکا ہوتا ہے۔

BackgroundTasks کہاں خاموشی سے کام drop کرتا ہے

ان میں سے ہر ایک production deployment میں ایک معمول کی، متوقع صورتحال ہے — کوئی edge case نہیں:

Deploys. rolling deploy پرانے process کو SIGTERM بھیجتا ہے۔ اگر کوئی background task اس وقت mid-flight ہو (یا ابھی شروع ہی نہ ہوا ہو کیونکہ وہ اسی event loop میں دوسرے کام کے پیچھے queue ہوا ہو) اور process کی grace period ختم ہونے پر اسے SIGKILL کر دیا جائے، تو وہ task مستقل طور پر ختم ہو جاتا ہے، اور اس بارے میں کچھ log بھی نہیں ہوتا۔

Autoscaling scale-down. mechanism وہی ہے جو deploy میں ہوتا ہے — ایک orchestrator (Kubernetes, ECS) کم load کے تحت کسی instance کو terminate کرنے کا فیصلہ کرتا ہے، اور اس instance پر چل رہا کوئی بھی BackgroundTasks کام اس کے ساتھ غائب ہو جاتا ہے۔

Process crashes اور OOM kills. memory leak یا اسی process میں کہیں اور unexpectedly بڑا request پورے worker کو OOM-kill کروا سکتا ہے، اور اس کے ساتھ ہر pending background task بھی ختم ہو جاتا ہے — حتیٰ کہ وہ tasks بھی جن کا crash کی اصل وجہ سے کوئی تعلق نہ ہو۔

Failure پر کوئی retry نہیں۔ اگر send_confirmation_email exception raise کرے — مثلاً email provider timeout کر جائے — تو BackgroundTasks اسے retry نہیں کرتا۔ default طور پر exception نگل لی جاتی ہے (نظر صرف تب آتی ہے جب آپ نے اس کے لیے exception logging لگائی ہو)، اور task سادہ طور پر کبھی مکمل نہیں ہوتا۔ نہ کوئی dead-letter queue، نہ backoff، نہ دوسری کوشش۔

Cross-process visibility نہیں۔ اگر آپ کئی Uvicorn/Gunicorn workers چلا رہے ہیں، تو worker 2 پر schedule کیا گیا BackgroundTasks job worker 1 سے کسی بھی طرح منسلک نہیں ہوتا — آپ اسے inspect، retry، یا cancel کہیں سے بھی نہیں کر سکتے سوائے اسی exact process کے جس نے اسے schedule کیا تھا، اور اسی process کے logs ہی اس کے وجود کا واحد record ہوتے ہیں۔

ان میں سے کوئی بھی چیز BackgroundTasks کو broken نہیں بناتی۔ یہ اسے ایسے کام کے لیے ایک tool بناتی ہے جسے آپ واقعی کبھی کبھار کھونے کا خرچ برداشت کر سکتے ہوں — نہ کہ ایک general-purpose job queue جس نے صرف آسان API پہن رکھی ہو۔

Celery کیا اضافہ کرتی ہے

Celery کی architecture اوپر موجود ہر خلا کا براہِ راست جواب دیتی ہے، کیونکہ یہ “وہ request جس نے کام trigger کیا” اور “وہ process جو کام کرتا ہے” کے درمیان ایک durable، independent layer رکھتی ہے:

  • ایک message broker (Redis/RabbitMQ) جو task کو persist کرتا ہے۔ جیسے ہی .delay() call ہوتی ہے، task serialize ہو کر broker میں لکھ دیا جاتا ہے — FastAPI process کے lifecycle سے آزاد۔ اگر API process ایک millisecond بعد مر بھی جائے، task broker میں محفوظ رہتا ہے۔
  • آزاد worker processes۔ Celery workers الگ processes ہوتے ہیں (اکثر الگ containers یا hosts بھی) جو broker سے tasks اٹھاتے ہیں۔ آپ کی API کا deploy انہیں نہیں چھیڑتا؛ اور workers کا deploy آپ کی API کو نہیں چھیڑتا۔
  • backoff کے ساتھ built-in retries۔ کوئی task max_retries اور backoff policy define کر سکتا ہے، اس لیے transient failure — جیسے downstream API کچھ دیر کے لیے unavailable ہو — خاموشی سے ختم ہونے کے بجائے خودکار طور پر retry ہو جاتا ہے۔
  • ایک results backend۔ task state (pending، success، failure، اور return value) بعد میں کسی بھی process سے query کی جا سکتی ہے، جس سے “کیا یہ واقعی مکمل ہوا؟” ایک قابلِ جواب سوال بن جاتا ہے، محض logs کھنگالنے کا کام نہیں رہتا۔
  • Scheduling اور rate limiting۔ periodic tasks (celery beat)، per-task-type rate limits، اور priority queues first-class features ہیں، وہ چیزیں نہیں جنہیں آپ کو BackgroundTasks کے اوپر خود سے بنانا پڑے۔

اس کے بدلے میں حقیقی infrastructure درکار ہوتا ہے: ایک broker جسے چلانا اور monitor کرنا ہو، worker processes جنہیں الگ deploy اور scale کرنا ہو، اور ایک واقعی زیادہ پیچیدہ mental model — task serialization، idempotency، اور broker connection handling اب آپ کی ذمہ داری ہیں، اس انداز میں جس طرح BackgroundTasks کے ساتھ نہیں تھیں۔

فیصلہ سازی کا فریم ورک

تین سوال تقریباً ہر case کا فیصلہ کر دیتے ہیں:

1. کیا آپ اس task کے مکمل طور پر، خاموشی سے، بغیر retry کے ضائع ہو جانے کا خرچ برداشت کر سکتے ہیں؟
اگر ہاں — metrics ping، best-effort cache warm، analytics event — تو BackgroundTasks کافی ہے اور Celery شامل کرنا محض overhead ہوگا۔ اگر نہیں — پیسے سے متعلق کوئی بھی چیز، ایسی کوئی بھی چیز جس کے نتیجے کا صارف واضح طور پر انتظار کر رہا ہو، یا ایسی کوئی بھی چیز جس پر compliance یا audit requirement ہو — تو آپ کو Celery کی durability چاہیے۔

2. کیا task کو deploy یا scale-down event survive کرنا ضروری ہے؟
BackgroundTasks کا کام صرف اسی صورت survive کرتا ہے جب اسے schedule کرنے والا process اتنی دیر زندہ رہے کہ وہ اسے مکمل کر لے۔ اگر آپ کا deploy cadence زیادہ frequent ہے (دن میں کئی بار، جیسا کہ CI/CD کے ساتھ عام ہے) اور tasks آپ کی graceful-shutdown window سے زیادہ وقت لیتے ہیں، تو BackgroundTasks نایاب نہیں بلکہ پیش گوئی کے مطابق کام کھوئے گا۔

3. کیا task کو retry policy، scheduling، یا cross-process visibility چاہیے؟
اگر failure پر خودکار retry چاہیے، اگر task کو کسی request سے آزاد schedule پر چلنا ہے، یا اگر آپ کو task status کسی دوسرے process سے check کرنا ہے (admin dashboard، الگ API)، تو یہی وہ کام ہے جس کے لیے خاص طور پر Celery کا broker اور results backend ہیں — BackgroundTasks کے پاس ان تینوں میں سے کسی کے لیے کوئی mechanism نہیں۔

SignalBackgroundTasksCelery
Task durationسیکنڈز، منٹس نہیںسیکنڈز سے گھنٹوں تک
Loss toleranceمکمل برداشتdurability درکار
Retry on failurebuilt in نہیںbuilt in، backoff کے ساتھ
Process restart survive کرتا ہےنہیںہاں
Cross-process visibilityنہیںہاں (results backend)
درکار infrastructureکچھ نہیںBroker + worker processes
Scheduling (cron-like)نہیںہاں (celery beat)

Hybrid patterns

زیادہ تر mature FastAPI codebases جان بوجھ کر دونوں استعمال کرتی ہیں، بجائے اس کے کہ پوری app کے لیے ایک ہی tool چن لیا جائے۔ ایک عام اور مؤثر تقسیم یہ ہے: ایسے کام کے لیے BackgroundTasks استعمال کریں جسے دوبارہ کرنا سستا ہو یا جو واقعی disposable ہو، اور ایسی ہر چیز کو Celery کے ذریعے dispatch کریں جس میں durability یا retry requirement ہو — اکثر اسی endpoint سے۔

@app.post("/orders")
async def create_order(payload: OrderCreate, background_tasks: BackgroundTasks):
    order = await create_order_record(payload)

    # Disposable — fine to lose occasionally, no retry needed
    background_tasks.add_task(log_analytics_event, "order_created", order.id)

    # Durable — must survive a deploy, needs a retry policy
    send_order_confirmation.delay(order.id)

    return order

سادہ اصول یہ ہے: اگر post-mortem میں یہ معلوم ہونے پر آپ پریشان ہوں کہ کوئی task خاموشی سے کبھی چلا ہی نہیں، تو وہ Celery میں ہونا چاہیے۔ اگر آپ کندھے اچکا کر بات ٹال دیں، تو BackgroundTasks ہی درست مقدار کی tooling ہے۔

Code examples

Celery کی ایک minimal setup جو اوپر والے framework کی عکاسی کرتی ہے — واقعی اہم task کے لیے exponential backoff کے ساتھ retries:

# celery_app.py
from celery import Celery

celery_app = Celery(
    "worker",
    broker="redis://localhost:6379/0",
    backend="redis://localhost:6379/1",
)

@celery_app.task(
    bind=True,
    max_retries=5,
    default_retry_delay=10,  # seconds, before backoff kicks in
)
def send_order_confirmation(self, order_id: int):
    try:
        order = fetch_order(order_id)
        email_client.send(order.customer_email, render_receipt(order))
    except EmailProviderTimeout as exc:
        # exponential-ish backoff: 10s, 20s, 40s...
        raise self.retry(exc=exc, countdown=10 * (2 ** self.request.retries))
# app/orders/router.py
from app.workers.celery_app import send_order_confirmation

@router.post("/")
async def create_order_endpoint(payload: OrderCreate):
    order = await create_order(payload)
    send_order_confirmation.delay(order.id)
    return order

.delay(order.id) فوری return کرتی ہے — یہ صرف task کو broker پر enqueue کرتی ہے — اس لیے endpoint کا response time متاثر نہیں ہوتا، جبکہ completion کی اصل guarantee اب FastAPI process کے بجائے Celery کے broker اور retry policy میں رہتی ہے۔ اس طرح کی module boundary — یعنی ایک workers/ package جس میں router dispatch تو کرتا ہے مگر اس کے internals own نہیں کرتا — قدرتی طور پر اسی domain-driven layout میں fit ہوتی ہے جسے FastAPI Project Structure That Survives Growth میں بیان کیا گیا ہے۔

Celery کے ہلکے alternatives

Celery واحد durable option نہیں ہے، اور async-first FastAPI codebase کے لیے اکثر یہ سب سے قدرتی fit بھی نہیں ہوتی — Celery کا worker model asyncio سے پہلے کا ہے اور async tasks کو first-class design کے بجائے بعد میں جوڑی گئی feature کے طور پر برتتا ہے۔

arq ایک Redis-backed queue ہے جو ابتدا ہی سے خاص طور پر asyncio کے لیے بنائی گئی ہے۔ task functions async def ہوتے ہیں، workers اپنا event loop چلاتے ہیں، اور synchronous-to-async bridging کے بارے میں سوچنے کی ضرورت نہیں پڑتی:

# worker.py
async def send_order_confirmation(ctx, order_id: int):
    order = await fetch_order(order_id)
    await email_client.send_async(order.customer_email, render_receipt(order))

class WorkerSettings:
    functions = [send_order_confirmation]
    redis_settings = RedisSettings(host="localhost")
# dispatching from FastAPI
redis = await create_pool(RedisSettings(host="localhost"))
await redis.enqueue_job("send_order_confirmation", order.id)

Dramatiq اور RQ بھی اسی دائرے میں آتے ہیں — Celery سے آسان setup، Redis بطور broker، اور comparatively چھوٹی feature surface (مثلاً RQ کے core میں celery beat جیسی scheduling نہیں) کے بدلے کم operational overhead۔

اوپر دیا گیا decision framework اس سے قطع نظر لاگو رہتا ہے کہ آپ کون سی durable queue چنتے ہیں — سوال کبھی خاص طور پر “Celery یا کچھ نہیں” نہیں تھا، بلکہ یہ تھا کہ “کیا اس task کو broker-backed durability کی ضرورت ہے بھی یا نہیں”۔ جب آپ کو اس کے ecosystem کی ضرورت ہو — mature scheduling، routing، اور monitoring tooling جس تک نئے alternatives ابھی پہنچ رہے ہیں — تو Celery اب بھی درست default رہتی ہے، لیکن اگر آپ greenfield async FastAPI service بنا رہے ہیں، تو arq کو پہلے evaluate کرنا چاہیے، خاص طور پر اس لیے کہ یہ ورنہ async-first codebase میں sync-first task runner ملانے سے بچاتی ہے۔

عام غلطیاں

غلطی: payment یا compliance سے متعلق کسی بھی چیز کے لیے BackgroundTasks استعمال کرنا۔ خاموشی سے drop ہوئی charge confirmation یا audit log entry ایک business problem ہے، محض technical inconvenience نہیں۔ حل: ہر وہ چیز جس پر قانونی، مالی، یا audit requirement ہو، بغیر کسی استثنا کے Celery کے ذریعے جائے۔

غلطی: یہ فرض کر لینا کہ Celery tasks خودکار طور پر idempotent ہوتے ہیں۔ retry ہونے والا task پوری function کو دوبارہ چلاتا ہے — اگر send_order_confirmation کو دو بار چلانا محفوظ نہ ہو، تو partial failure کے بعد retry double-send کا سبب بن سکتی ہے۔ حل: جب بھی retries enabled ہوں، tasks کو idempotent انداز میں design کریں (check-before-act، یا idempotency keys استعمال کریں)۔

غلطی: واقعی long-running کام کو BackgroundTasks میں ڈال دینا۔ ایسا task جو آپ کے API workers کے اسی process میں کئی منٹ چلے، request handling کے ساتھ انہی resources پر مقابلہ کرتا ہے۔ حل: چند سیکنڈ سے زیادہ کا ہر کام الگ worker pool میں ہونا چاہیے، اور یہی چیز Celery فراہم کرتی ہے۔

غلطی: ایک ہی کم اہمیت والے task کے لیے Celery کھڑی کر دینا۔ broker اور worker fleet کی operational cost ایک best-effort analytics call کے لیے justify نہیں ہوتی۔ حل: جب تک کوئی واضح durability یا retry requirement سامنے نہ آئے، BackgroundTasks کو default رکھیں۔

غلطی: Celery worker health کو monitor نہ کرنا۔ crashed یا backed-up worker fleet خاموشی سے بڑھتا ہوا backlog جمع کرتی رہتی ہے، اور صارف کی طرف سے کوئی واضح علامت اس وقت تک نہیں آتی جب تک مسئلہ شدید نہ ہو جائے۔ حل: queue depth اور worker liveness (Flower، یا آپ کے APM کی Celery integration) کو first-class production metric کے طور پر monitor کریں۔

Production best practices

  • BackgroundTasks کو default رکھیں اور سوچ سمجھ کر upgrade کریں۔ Celery infrastructure اس وقت تک نہ کھڑی کریں جب تک کسی حقیقی task کو اس کی guarantees کی واقعی ضرورت نہ ہو۔
  • Celery tasks کو default طور پر idempotent بنائیں۔ یہ فرض کریں کہ ہر task کم از کم ایک بار retry ہوگا، کیونکہ آخرکار ایسا ہو کر رہتا ہے۔
  • واضح retry limits اور backoff set کریں، unlimited retries کبھی نہیں۔ ایسا task جو مستقل طور پر ٹوٹے ہوئے dependency کے خلاف ہمیشہ retry کرتا رہے، بس ایک دوسری قسم کا incident بن جاتا ہے۔
  • Task dispatch اور completion کو الگ الگ log کریں۔ یہ جاننا کہ task schedule ہوا تھا، یہ جاننے کے برابر نہیں کہ وہ successful بھی ہوا — دونوں کو instrument کریں۔
  • Queue depth کو alertable metric سمجھیں۔ بڑھتا ہوا، unprocessed Celery backlog downstream outage کی ابتدائی علامات میں سے ایک ہے۔

خلاصہ

BackgroundTasks اور Celery ایک ہی مسئلے کے مقابل حل نہیں ہیں — یہ دو واقعی مختلف durability requirements کے لیے درست tools ہیں، اور غلطی setup effort کی بنیاد پر انتخاب کرنا ہے بجائے اس کے کہ دیکھا جائے task کے دوران deploy آ جائے تو کیا ہوتا ہے۔ اگر کام کا خاموشی سے ضائع ہو جانا واقعی مسئلہ ہوگا، تو یہی آپ کا جواب ہے، چاہے آج BackgroundTasks کتنی ہی آسان کیوں نہ لگ رہی ہو۔ زیادہ تر production FastAPI apps آخرکار جان بوجھ کر دونوں استعمال کرتی ہیں، جب وہ ایک حد سے زیادہ drop ہوئے task کا نقصان دیکھ چکی ہوتی ہیں۔

کیا آپ واقعی جانتے ہیں کہ اگلی بار deploy کے وقت آپ کے in-flight background tasks کے ساتھ کیا ہوگا؟

مزید مضامین