65 lines
3.5 KiB
Python
65 lines
3.5 KiB
Python
# Mengimpor modul Any untuk type hint fleksibel dari modul standar typing Python
|
|
from typing import Any
|
|
# Mengimpor fungsi create_engine dari SQLAlchemy untuk membuat engine penghubung ke database
|
|
from sqlalchemy import create_engine
|
|
# Mengimpor sessionmaker dari SQLAlchemy ORM untuk membuat factory pembentuk sesi transaksi database
|
|
from sqlalchemy.orm import sessionmaker
|
|
# Mengimpor objek konfigurasi global settings yang berisi DATABASE_URL
|
|
from app.config.config import settings
|
|
|
|
# Memeriksa apakah database yang digunakan adalah SQLite berdasarkan awalan protokol connection string
|
|
is_sqlite = settings.DATABASE_URL.startswith("sqlite")
|
|
# Jika database adalah SQLite, nonaktifkan check_same_thread agar session dapat digunakan lintas thread FastAPI; jika MySQL/PostgreSQL gunakan dictionary kosong
|
|
connect_args = {"check_same_thread": False} if is_sqlite else {}
|
|
|
|
# Menyiapkan dictionary parameter konfigurasi untuk SQLAlchemy engine
|
|
engine_kwargs: dict[str, Any] = {
|
|
# Argumen koneksi level driver (khusus SQLite atau kosong untuk MySQL)
|
|
"connect_args": connect_args,
|
|
# Menentukan apakah setiap query mentah dicetak ke terminal (False = dinonaktifkan demi performa dan kebersihan log)
|
|
"echo": False, # Matikan SQL echo agar tidak memperlambat I/O console terminal
|
|
}
|
|
|
|
# Jika bukan SQLite (misal MySQL pada produksi atau pengembangan lokal), tambahkan konfigurasi connection pooling
|
|
if not is_sqlite:
|
|
engine_kwargs.update({
|
|
# pool_pre_ping: Memeriksa kesehatan koneksi sebelum query dijalankan untuk mencegah error koneksi mati (MySQL server has gone away)
|
|
"pool_pre_ping": True,
|
|
# pool_recycle: Mendaur ulang koneksi database setiap 1800 detik (30 menit) agar tidak diputus paksa oleh timeout server MySQL
|
|
"pool_recycle": 1800,
|
|
# pool_size: Jumlah koneksi database tetap yang dipertahankan dalam memory pool
|
|
"pool_size": 15,
|
|
# max_overflow: Jumlah koneksi tambahan maksimal yang diizinkan dibuat saat lalu lintas request sedang tinggi
|
|
"max_overflow": 25,
|
|
})
|
|
|
|
# Membuat instance Engine SQLAlchemy sebagai gerbang utama komunikasi antara aplikasi FastAPI dan server database
|
|
engine = create_engine(
|
|
# URL database (contoh: mysql+pymysql://root:@localhost:3306/tracerstudy_db)
|
|
settings.DATABASE_URL,
|
|
# Unpack dictionary argumen konfigurasi engine yang telah disesuaikan
|
|
**engine_kwargs
|
|
)
|
|
|
|
# Membuat class factory SessionLocal untuk menghasilkan sesi database baru pada setiap request
|
|
# autocommit=False: Transaksi tidak langsung di-commit otomatis (memungkinkan commit/rollback manual demi konsistensi data)
|
|
# autoflush=False: Mencegah perubahan di-flush ke database sebelum commit atau query eksplisit
|
|
# bind=engine: Mengikat sesi ini ke engine database yang telah dibuat
|
|
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
|
|
|
# Fungsi Dependency Injection untuk FastAPI yang menyediakan sesi database ke setiap endpoint API
|
|
def get_db():
|
|
"""
|
|
Menghasilkan (yields) instance sesi database untuk satu request HTTP.
|
|
Memastikan koneksi selalu ditutup (closed) di blok finally bahkan jika terjadi error selama eksekusi request.
|
|
"""
|
|
# Membuka sesi database baru dari factory SessionLocal
|
|
db = SessionLocal()
|
|
try:
|
|
# Memberikan sesi database aktif ke controller/endpoint yang memanggilnya
|
|
yield db
|
|
finally:
|
|
# Menutup sesi database setelah request selesai diproses agar koneksi dikembalikan ke connection pool dan tidak terjadi memory leak
|
|
db.close()
|
|
|