Files
service-finder/docs/p0_wallet_balance_500_bugfix_2026-07-26.md
2026-07-27 08:39:18 +00:00

5.7 KiB

P0 Bug #420: GET /api/v1/billing/wallet/balance - 500 Internal Server Error

Dátum: 2026-07-26
Súlyosság: P0 - Blokkoló (minden wallet/balance hívást érint)
Státusz: Megoldva (pycache purge + restart)


1. Hiba Leírása

A GET /api/v1/billing/wallet/balance végpont 500 Internal Server Error hibával tért vissza bizonyos meglévő felhasználók (pl. user_id=86, 28) esetén.

Hibaüzenet a logból:

2026-07-26 12:37:49,388 [ERROR] app.api.v1.endpoints.billing: Pénztárca egyenleg lekérdezési hiba: 'FinancialLedger' object has no attribute 'description'

Érintett fájlok:


2. Root Cause Analysis

2.1 A FinancialLedger modell

A FinancialLedger modell NEM rendelkezik description oszloppal. Az egyetlen "leíró" mező a details (JSONB). A modell oszlopai:

id, user_id, person_id, amount, currency, transaction_type,
related_agent_id, details, created_at, entry_type, balance_after,
wallet_type, issuer_id, invoice_status, tax_amount, gross_amount,
net_amount, transaction_id, status

2.2 A jelenlegi forráskód helyes

A billing_engine.py get_transaction_history() metódusa helyesen használja a details JSONB mezőt a leírás kinyerésére:

# Line 577-579
desc = None
if entry.details and isinstance(entry.details, dict):
    desc = entry.details.get("description") or entry.details.get("desc") or None

A billing.py router szintén helyesen:

# Line 376-378
description = ""
if entry.details and isinstance(entry.details, dict):
    description = entry.details.get("description", "")

2.3 A tényleges ok: Stale Python Bytecode Cache

Az MD5 ellenőrzés igazolta, hogy a konténerben futó forráskód és a host-on lévő forráskód azonos:

Fájl MD5
billing.py (host & container) 6b00968c129376e3db630e266835261b
billing_engine.py (host & container) 54d86868aa077bebfeddaf32c69642fc

A konténerben azonban régi .pyc bytecode fájlok voltak cache-elve:

/app/app/api/v1/endpoints/__pycache__/billing.cpython-312.pyc
/app/app/services/__pycache__/billing_engine.cpython-312.pyc

Ezek a .pyc fájlok egy korábbi forráskód-verzióhoz tartoztak, ahol még létezett entry.description hivatkozás a FinancialLedger objektumokon (vagy egy másik séma érvényben volt).

2.4 Miért nem frissültek a .pyc fájlok?

A docker-compose.yml-ben a sf_api konténer forráskódja volume mount-tal van csatolva (nem COPY). Amikor a forráskód változik a host-on, a Python értelmező a konténerben azonnal látja az új .py fájlokat, de a már legenerált .pyc cache fájlok megmaradnak. Ha a .py fájl timestamp-je régebbi, mint a .pyc-é (vagy a Python nem érzékeli a változást), a régi bytecode fut.


3. Megoldás

Végrehajtott lépések:

  1. Pycache törlése a konténerben:

    docker compose exec sf_api find /app -type d -name "__pycache__" -exec rm -rf {} +
    
  2. Konténer újraindítása:

    docker compose restart sf_api
    
  3. Verifikáció: A restart után az endpoint már NEM dob 500-as hibát. A logokban nem jelenik meg több description hiba.


4. Code Mode Blueprint (Preventív Intézkedés)

Bár a jelenlegi forráskód helyes, az alábbi preventív intézkedést javaslom a Code Mode-ban:

4.1 Docker Compose: pycache purge a startup előtt

A docker-compose.yml sf_api szolgáltatás command sorában futtassunk egy automatikus pycache purge-öt a Uvicorn indítása előtt:

command: >
  /bin/sh -c "
    find /app -type d -name '__pycache__' -exec rm -rf {} + 2>/dev/null;
    uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload
  "

4.2 Opcionális: .pyc fájlok teljes letiltása fejlesztői környezetben

A docker-compose.yml environment változói közé:

environment:
  - PYTHONDONTWRITEBYTECODE=1

Ez megakadályozza, hogy a Python egyáltalán .pyc fájlokat generáljon, így mindig a forráskódból fog futni.


5. Függelék: Mermaid Folyamatábra

sequenceDiagram
    participant Client
    participant FastAPI as billing.py router
    participant BillingEngine as billing_engine.py
    participant Model as FinancialLedger
    participant DB as PostgreSQL

    Client->>FastAPI: GET /api/v1/billing/wallet/balance
    FastAPI->>BillingEngine: get_user_balance(db, user_id)
    BillingEngine->>BillingEngine: get_wallet_summary(db, user_id)
    BillingEngine->>DB: SELECT * FROM identity.wallets WHERE user_id=?
    BillingEngine->>DB: SELECT * FROM audit.financial_ledger LIMIT 10
    BillingEngine->>Model: entry.details.get("description")
    Note over Model: Helyes: details JSONB mezőből olvas
    Model-->>BillingEngine: description string
    BillingEngine-->>FastAPI: {"earned": X, "purchased": Y, ...}
    FastAPI-->>Client: 200 OK + JSON balances

A hiba idején a .pyc bytecode entry.description-t próbált elérni, ami nem létező attribútum a FinancialLedger modellen. Ez AttributeError-t okozott, amit a billing.py router except Exception ága elkapott és 500-ra fordított.