Skip to content

Commit 4bfe6ff

Browse files
committed
Revert "🔥 Remove Celery and Flower, they are currently not used nor recommended (fastapi#694)"
This reverts commit 1e256bc.
1 parent 8e20017 commit 4bfe6ff

20 files changed

+545
-8
lines changed

‎.env‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ POSTGRES_PASSWORD=-7vcO6peCJz0y0AcYUl8eM9m-LhC4NPsG9WLNe75hrs
3333

3434
SENTRY_DSN=
3535

36+
# Flower
37+
FLOWER_BASIC_AUTH=admin:changethis
38+
3639
# Configure these with your own Docker registry images
3740
DOCKER_IMAGE_BACKEND=backend
41+
DOCKER_IMAGE_CELERYWORKER=celery
3842
DOCKER_IMAGE_FRONTEND=frontend

‎.github/workflows/deploy-production.yml‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ jobs:
2323
EMAILS_FROM_EMAIL: ${{ secrets.EMAILS_FROM_EMAIL }}
2424
POSTGRES_PASSWORD: ${{ secrets.POSTGRES_PASSWORD }}
2525
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
26+
FLOWER_BASIC_AUTH: ${{ secrets.FLOWER_BASIC_AUTH }}
2627
steps:
2728
- name: Checkout
2829
uses: actions/checkout@v4

‎.github/workflows/deploy-staging.yml‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ jobs:
2323
EMAILS_FROM_EMAIL: ${{ secrets.EMAILS_FROM_EMAIL }}
2424
POSTGRES_PASSWORD: ${{ secrets.POSTGRES_PASSWORD }}
2525
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
26+
FLOWER_BASIC_AUTH: ${{ secrets.FLOWER_BASIC_AUTH }}
2627
steps:
2728
- name: Checkout
2829
uses: actions/checkout@v4

‎README.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ The input variables, with their default values (some auto generated) are:
210210
- `emails_from_email`: (default: `"[email protected]"`) The email account to send emails from, you can set it later in .env.
211211
- `postgres_password`: (default: `"changethis"`) The password for the PostgreSQL database, stored in .env, you can generate one with the method above.
212212
- `sentry_dsn`: (default: "") The DSN for Sentry, if you are using it, you can set it later in .env.
213+
- `flower_basic_auth`: (default: `"admin:changethis"`) The basic auth for Flower, you can set it later in .env.
213214

214215
## Backend Development
215216

‎backend/README.md‎

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ Automatic interactive documentation with Swagger UI (from the OpenAPI backend):
2323

2424
Adminer, database web administration: http://localhost:8080
2525

26+
Flower, administration of Celery tasks: http://localhost:5555
27+
2628
Traefik UI, to see how the routes are being handled by the proxy: http://localhost:8090
2729

2830
**Note**: The first time you start your stack, it might take a minute for it to be ready. While the backend waits for the database to be ready and configures everything. You can check the logs to monitor it.
@@ -63,6 +65,8 @@ Make sure your editor is using the correct Python virtual environment.
6365

6466
Modify or add SQLModel models for data and SQL tables in `./backend/app/models.py`, API endpoints in `./backend/app/api/`, CRUD (Create, Read, Update, Delete) utils in `./backend/app/crud.py`.
6567

68+
Add and modify tasks to the Celery worker in `./backend/app/worker.py`.
69+
6670
### Enabling Open User Registration
6771

6872
By default the backend has user registration disabled, but there's already a route to register users. If you want to allow users to register themselves, you can set the environment variable `USERS_OPEN_REGISTRATION` to `True` in the `.env` file.
@@ -163,7 +167,19 @@ docker compose exec backend bash /app/tests-start.sh -x
163167

164168
#### Test Coverage
165169

166-
When the tests are run, a file `htmlcov/index.html` is generated, you can open it in your browser to see the coverage of the tests.
170+
Because the test scripts forward arguments to `pytest`, you can enable test coverage HTML report generation by passing `--cov-report=html`.
171+
172+
To run the local tests with coverage HTML reports:
173+
174+
```Bash
175+
DOMAIN=backend sh ./scripts/test-local.sh --cov-report=html
176+
```
177+
178+
To run the tests in a running stack with coverage HTML reports:
179+
180+
```bash
181+
docker compose exec backend bash /app/tests-start.sh --cov-report=html
182+
```
167183

168184
### Migrations
169185

‎backend/app/api/routes/utils.py‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,26 @@
22
from pydantic.networks import EmailStr
33

44
from app.api.deps import get_current_active_superuser
5+
from app.core.celery_app import celery_app
56
from app.models import Message
67
from app.utils import generate_test_email, send_email
78

89
router = APIRouter()
910

1011

12+
@router.post(
13+
"/test-celery/",
14+
dependencies=[Depends(get_current_active_superuser)],
15+
status_code=201,
16+
)
17+
def test_celery(body: Message) -> Message:
18+
"""
19+
Test Celery worker.
20+
"""
21+
celery_app.send_task("app.worker.test_celery", args=[body.message])
22+
return Message(message="Word received")
23+
24+
1125
@router.post(
1226
"/test-email/",
1327
dependencies=[Depends(get_current_active_superuser)],
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from celery import Celery
2+
3+
celery_app = Celery("worker", broker="amqp://guest@queue//")
4+
5+
celery_app.conf.task_routes = {"app.worker.test_celery": "main-queue"}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
from fastapi.testclient import TestClient
2+
3+
from app.core.config import settings
4+
5+
6+
def test_celery_worker_test(
7+
client: TestClient, superuser_token_headers: dict[str, str]
8+
) -> None:
9+
data = {"message": "test"}
10+
r = client.post(
11+
f"{settings.API_V1_STR}/utils/test-celery/",
12+
json=data,
13+
headers=superuser_token_headers,
14+
)
15+
response = r.json()
16+
assert response["message"] == "Word received"
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
from unittest.mock import MagicMock
2+
3+
from pytest_mock import MockerFixture
4+
from sqlmodel import select
5+
6+
from app.celeryworker_pre_start import init, logger
7+
8+
9+
def test_init_successful_connection(mocker: MockerFixture) -> None:
10+
engine_mock = MagicMock()
11+
12+
session_mock = MagicMock()
13+
exec_mock = MagicMock(return_value=True)
14+
session_mock.configure_mock(**{"exec.return_value": exec_mock})
15+
mocker.patch("sqlmodel.Session", return_value=session_mock)
16+
17+
mocker.patch.object(logger, "info")
18+
mocker.patch.object(logger, "error")
19+
mocker.patch.object(logger, "warn")
20+
21+
try:
22+
init(engine_mock)
23+
connection_successful = True
24+
except Exception:
25+
connection_successful = False
26+
27+
assert (
28+
connection_successful
29+
), "The database connection should be successful and not raise an exception."
30+
31+
assert session_mock.exec.called_once_with(
32+
select(1)
33+
), "The session should execute a select statement once."

‎backend/app/worker.py‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import sentry_sdk
2+
3+
from app.core.celery_app import celery_app
4+
from app.core.config import settings
5+
6+
if settings.SENTRY_DSN:
7+
sentry_sdk.init(dsn=str(settings.SENTRY_DSN))
8+
9+
10+
@celery_app.task(acks_late=True)
11+
def test_celery(word: str) -> str:
12+
return f"test task return {word}"

0 commit comments

Comments
 (0)