Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion app/core/logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import sys
from typing import Any

import orjson
import structlog

from app.core.config import settings
Expand All @@ -18,7 +19,7 @@ def setup_logging() -> None:
processors.append(structlog.dev.ConsoleRenderer())
else:
processors.append(structlog.processors.dict_tracebacks)
processors.append(structlog.processors.JSONRenderer())
processors.append(structlog.processors.JSONRenderer(serializer=orjson.dumps))
structlog.configure(
processors=processors, logger_factory=structlog.stdlib.LoggerFactory()
)
Expand Down
2 changes: 2 additions & 0 deletions app/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import structlog
from fastapi import FastAPI
from fastapi.responses import ORJSONResponse
from prometheus_fastapi_instrumentator import Instrumentator
from redis.asyncio import Redis

Expand Down Expand Up @@ -39,6 +40,7 @@ async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]:
description='FairDrop API HL B2B Dropshipping Platform',
version='0.1.0',
lifespan=lifespan,
default_response_class=ORJSONResponse,
)

Instrumentator().instrument(app).expose(app)
Expand Down
12 changes: 8 additions & 4 deletions app/services/inventory/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,17 +43,21 @@ class Reservation(Base):

id: Mapped[UUID] = mapped_column(primary_key=True, default=uuid4)
qty_reserved: Mapped[int] = mapped_column(Integer, nullable=False, default=1)
user_id: Mapped[UUID] = mapped_column(ForeignKey('users.id'), nullable=False)
product_id: Mapped[UUID] = mapped_column(ForeignKey('products.id'), nullable=False)
user_id: Mapped[UUID] = mapped_column(
ForeignKey('users.id'), nullable=False, index=True
)
product_id: Mapped[UUID] = mapped_column(
ForeignKey('products.id'), nullable=False, index=True
)
status: Mapped[str] = mapped_column(
String(), nullable=False, default='pending', index=True
)
idempotency_key: Mapped[str] = mapped_column(String(), nullable=False, unique=True)
order_id: Mapped[UUID | None] = mapped_column(
ForeignKey('orders.id'), nullable=True
ForeignKey('orders.id'), nullable=True, index=True
)
expires_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), nullable=False
DateTime(timezone=True), nullable=False, index=True
)
created_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), server_default=func.now(), index=True
Expand Down
14 changes: 10 additions & 4 deletions app/services/orders/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,11 @@ class Order(Base):
__tablename__ = 'orders'

id: Mapped[UUID] = mapped_column(primary_key=True, default=uuid4)
user_id: Mapped[UUID] = mapped_column(ForeignKey('users.id'), nullable=False)
user_id: Mapped[UUID] = mapped_column(
ForeignKey('users.id'), nullable=False, index=True
)
status: Mapped[OrderStatus] = mapped_column(
Enum(OrderStatus), nullable=False, default=OrderStatus.PENDING
Enum(OrderStatus), nullable=False, default=OrderStatus.PENDING, index=True
)
total_amount: Mapped[Decimal] = mapped_column(
Numeric(DECIMAL_PRECISION, DECIMAL_SCALE), nullable=False
Expand All @@ -54,8 +56,12 @@ class OrderItem(Base):
__tablename__ = 'order_items'

id: Mapped[UUID] = mapped_column(primary_key=True, default=uuid4)
order_id: Mapped[UUID] = mapped_column(ForeignKey('orders.id'), nullable=False)
product_id: Mapped[UUID] = mapped_column(ForeignKey('products.id'), nullable=False)
order_id: Mapped[UUID] = mapped_column(
ForeignKey('orders.id'), nullable=False, index=True
)
product_id: Mapped[UUID] = mapped_column(
ForeignKey('products.id'), nullable=False, index=True
)

order: Mapped['Order'] = relationship('Order', back_populates='items')
product_name: Mapped[str] = mapped_column(String(), nullable=False)
Expand Down
13 changes: 8 additions & 5 deletions app/shared/decorators.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import json
from collections.abc import Callable
from functools import wraps
from typing import Any

import orjson
from fastapi import HTTPException, Request, Response, status
from fastapi.encoders import jsonable_encoder
from fastapi.responses import JSONResponse
from pydantic import BaseModel

from app.core.config import settings
Expand Down Expand Up @@ -39,14 +38,18 @@ async def wrapper(*args: Any, **kwargs: Any) -> Response | Any:
redis_key = f'idempotency:{idempotency_key}'
cached_response = await redis_client.get(redis_key)
if cached_response:
data = json.loads(cached_response)
return JSONResponse(content=data, status_code=status.HTTP_200_OK)
data = orjson.loads(cached_response)
return Response(
content=orjson.dumps(data),
status_code=status.HTTP_200_OK,
media_type='application/json',
)
response = await func(*args, **kwargs)
if isinstance(response, BaseModel):
json_str_to_cache = response.model_dump_json()
else:
json_data = jsonable_encoder(response)
json_str_to_cache = json.dumps(json_data)
json_str_to_cache = orjson.dumps(json_data).decode()
await redis_client.setex(redis_key, ttl_seconds, json_str_to_cache)
return response

Expand Down
29 changes: 29 additions & 0 deletions migrations/versions/2a03cc82fdc7_add_performance_indexes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
"""Add performance indexes

Revision ID: 2a03cc82fdc7
Revises: cdede027cf9b
Create Date: 2026-03-12 15:35:23.227561

"""

from collections.abc import Sequence

# revision identifiers, used by Alembic.
revision: str = '2a03cc82fdc7'
down_revision: str | Sequence[str] | None = 'cdede027cf9b'
branch_labels: str | Sequence[str] | None = None
depends_on: str | Sequence[str] | None = None


def upgrade() -> None:
"""Upgrade schema."""
# ### commands auto generated by Alembic - please adjust! ###
pass
# ### end Alembic commands ###


def downgrade() -> None:
"""Downgrade schema."""
# ### commands auto generated by Alembic - please adjust! ###
pass
# ### end Alembic commands ###
57 changes: 57 additions & 0 deletions migrations/versions/cdede027cf9b_add_performance_indexes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
"""Add performance indexes

Revision ID: cdede027cf9b
Revises: da065d87e52a
Create Date: 2026-03-12 15:35:08.784099

"""

from collections.abc import Sequence

from alembic import op

# revision identifiers, used by Alembic.
revision: str = 'cdede027cf9b'
down_revision: str | Sequence[str] | None = 'da065d87e52a'
branch_labels: str | Sequence[str] | None = None
depends_on: str | Sequence[str] | None = None


def upgrade() -> None:
"""Upgrade schema."""
# ### commands auto generated by Alembic - please adjust! ###
op.create_index(
op.f('ix_order_items_order_id'), 'order_items', ['order_id'], unique=False
)
op.create_index(
op.f('ix_order_items_product_id'), 'order_items', ['product_id'], unique=False
)
op.create_index(op.f('ix_orders_status'), 'orders', ['status'], unique=False)
op.create_index(op.f('ix_orders_user_id'), 'orders', ['user_id'], unique=False)
op.create_index(
op.f('ix_reservations_expires_at'), 'reservations', ['expires_at'], unique=False
)
op.create_index(
op.f('ix_reservations_order_id'), 'reservations', ['order_id'], unique=False
)
op.create_index(
op.f('ix_reservations_product_id'), 'reservations', ['product_id'], unique=False
)
op.create_index(
op.f('ix_reservations_user_id'), 'reservations', ['user_id'], unique=False
)
# ### end Alembic commands ###


def downgrade() -> None:
"""Downgrade schema."""
# ### commands auto generated by Alembic - please adjust! ###
op.drop_index(op.f('ix_reservations_user_id'), table_name='reservations')
op.drop_index(op.f('ix_reservations_product_id'), table_name='reservations')
op.drop_index(op.f('ix_reservations_order_id'), table_name='reservations')
op.drop_index(op.f('ix_reservations_expires_at'), table_name='reservations')
op.drop_index(op.f('ix_orders_user_id'), table_name='orders')
op.drop_index(op.f('ix_orders_status'), table_name='orders')
op.drop_index(op.f('ix_order_items_product_id'), table_name='order_items')
op.drop_index(op.f('ix_order_items_order_id'), table_name='order_items')
# ### end Alembic commands ###
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ dependencies = [
'boto3-stubs[essential,s3]>=1.42.54',
'email-validator>=2.3.0',
'fastapi>=0.129.0',
'orjson>=3.11.7',
'passlib[bcrypt]==1.7.4',
'prometheus-fastapi-instrumentator>=7.1.0',
'pydantic-settings>=2.12.0',
Expand Down
Loading
Loading