Sitemap

Building an Async Processing System with FastAPI, Celery and RabbitMQ on Windows

4 min readApr 15, 2026

--

While building scalable systems, long running tasks (OCR, ML, file processing) should never block your API.

Get Shaik Sabiha Tarannum’s stories in your inbox

Join Medium for free to get updates from this writer.

That’s where:

  • FastAPI- handles requests
  • RabbitMQ- queues tasks
  • Celery- processes tasks asynchronously
Press enter or click to view image in full size
FastAPI, RabbitMQ + Celery Architecture

Initial Setup Guide

  1. Install Dependencies

Note: It is strongly recommended to use Python 3.11 for this setup. Newer versions such as Python 3.14 may introduce compatibility issues with libraries like Celery and asyncio, and are not yet considered stable for this use case.

2. Configure Environment Variables
Add the following path to your system’s Environment variables (Path)-

C:\Program Files\RabbitMQ Server\rabbitmq_server-4.2.5\sbi

3. Enable RabbitMQ management plugin
Open command prompt as administrator and run the following command

rabbitmq-plugins enable rabbitmq_management

4. Restart RabbitMQ service
Run the following commands as administrator

net stop RabbitMQ
net start RabbitMQ

5. Access RabbitMQ management dashboard
Open the browser and navigate to-

http://localhost:15672/

Default login credentials

  • Username- guest
  • Password- guest
Press enter or click to view image in full size
RabbitMQ Dashboard Login
Press enter or click to view image in full size
RabbitMQ Management Dashboard

Note-

  • RabbitMQ uses port 5672 for application-level communication (used by Celery and other clients).
  • The RabbitMQ Management Dashboard runs on port 15672 (accessible via browser). You can create a new user from the Admin tab → Add user.
  • Celery workers do not expose any ports — they communicate with RabbitMQ through the broker URL (typically via port 5672).
  • Celery is a worker (consumer), not a server. It does not listen for incoming requests

Project Structure

invoice-demo/
│
├── app.py
├── requirements.txt
├── local_run.bat
├── .env.stage
│
├── config/
│ └── celery_app.py
│
├── controllers/
│ └── task_controller.py
│
├── services/
│ └── task_service.py
  1. Environment File
.env.stage
ENV=stage

ALLOWED_ORIGINS=["http://localhost:5173"] #If UI is React + Vite

CELERY_BROKER_URL=amqp://guest:guest@localhost:5672//
CELERY_RESULT_BACKEND=rpc://

2. Celery Configuration

config/celery_app.py
from celery import Celery
import os
from dotenv import load_dotenv

env = os.getenv("ENV", "stage")
load_dotenv(f".env.{env}")

celery = Celery(
"demo_tasks",
broker=os.getenv("CELERY_BROKER_URL"),
backend=os.getenv("CELERY_RESULT_BACKEND"),
)

celery.conf.update(
task_serializer="json",
accept_content=["json"],
result_serializer="json",
timezone="UTC",
enable_utc=True,
imports=["services.task_service"]
)

3. Celery Task (Service Layer)

services/task_service.py
from config.celery_app import celery
import time

@celery.task(bind=True)
def long_running_task(self, number: int):
print(f"Processing number: {number}")

# simulate heavy work
time.sleep(5)

result = number * number

print(f"Completed: {result}")
return {"input": number, "result": result}

4. Controller (API Layer)

controllers/task_controller.py
from fastapi import APIRouter
from services.task_service import long_running_task

router = APIRouter(prefix="/tasks", tags=["Tasks"])

@router.post("/process")
async def process_number(number: int):
task = long_running_task.delay(number)

return {
"message": "Task submitted",
"task_id": task.id
}

5. FastAPI App

app.py
import uvicorn
import os
import json
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from controllers.task_controller import router as task_router

origins_str = os.getenv("ALLOWED_ORIGINS")

try:
ALLOWED_ORIGINS = json.loads(origins_str) if origins_str else ["*"]
except Exception:
ALLOWED_ORIGINS = ["*"]

app = FastAPI()

app.add_middleware(
CORSMiddleware,
allow_origins=ALLOWED_ORIGINS,
allow_methods=["*"],
allow_headers=["*"],
)

app.include_router(task_router)

if __name__ == "__main__":
uvicorn.run("app:app", host="0.0.0.0", port=8000, reload=True)

7. requirements.txt

fastapi                 # Web framework to build APIs (handles routing, validation, request/response)

uvicorn[standard] # ASGI server to run FastAPI app

python-dotenv # Loads environment variables from .env.stage file into the app

celery # Distributed task queue to run background/async jobs (like OCR processing)

kombu # Messaging library used internally by Celery to communicate with brokers (RabbitMQ)

amqp # Low-level AMQP protocol client used by kombu to talk to RabbitMQ

8. local_run.bat

@echo on
SETLOCAL

echo ==========================================
echo LOCAL RUN - FASTAPI + CELERY + RABBITMQ
echo ==========================================

cd /d %~dp0

set ENV=stage

REM ==========================================
REM STEP 1: Start RabbitMQ
REM ==========================================
echo Checking RabbitMQ...

sc query RabbitMQ | findstr /I "RUNNING" >nul

IF ERRORLEVEL 1 (
echo Starting RabbitMQ...
net start RabbitMQ >nul 2>&1

IF ERRORLEVEL 1 (
echo ERROR: Failed to start RabbitMQ!
pause
exit /b 1
)
) ELSE (
echo RabbitMQ already running.
)

timeout /t 5 >nul

REM ==========================================
REM STEP 2: Python ENV
REM ==========================================
if not exist ".venv" (
echo Creating virtual environment...
python -m venv .venv
)

call .venv\Scripts\activate.bat

echo Installing requirements...
pip install -r requirements.txt

REM ==========================================
REM STEP 3: Start Celery Worker
REM ==========================================
echo Starting Celery worker...

start cmd /k celery -A config.celery_app.celery worker --loglevel=info --pool=solo

timeout /t 3 >nul

REM ==========================================
REM STEP 4: Start FastAPI
REM ==========================================
echo Starting FastAPI...

uvicorn app:app --host 0.0.0.0 --port 8000 --reload

ENDLOCAL
pause

How to Test

  1. Start everything
local_run.bat

This will start the API and a terminal to check Celery logs will open like-

Press enter or click to view image in full size
Celery Worker is Ready

2. Open Swagger

http://localhost:8000/docs
Press enter or click to view image in full size
FastAPI Swagger

3. Call API

POST /tasks/process?number=5

4. Check Celery logs

Press enter or click to view image in full size
Celery Result Logging

Your setup is Ready !!!

P.S. If you’re interested in setting up the same architecture in a production environment — including IIS hosting, port configuration, and running RabbitMQ, Celery, and FastAPI as services — feel free to reach out.

--

--

Shaik Sabiha Tarannum
Shaik Sabiha Tarannum

Software Engineer@ HPE | Ex- NXP | Ex-WTEF Scholar@ TalentSprint