Frappe Framework
Lectures depuis une base secondaire (réplica)
Le décorateur read_only bascule frappe.db vers le réplica le temps de la fonction. Les rapports script et requête l’utilisent déjà.
Rôle
Par défaut, lectures et écritures vont sur la même base. Quand le volume ou la concurrence ralentit, on peut lire sur un réplica et écrire sur le primaire. Frappe sait séparer les deux. Il faut déjà un réplica MariaDB ou un cluster Galera.
site_config.json
"read_from_replica" : 1/0
"different_credentials_for_replica" : 1/0
"replica_host" : "IP address for replica"
"replica_db_port" : "Replica DB port"
"replica_db_name" : "Replica DB name"
"replica_db_password" : "Replica DB password"read_from_replica active ou coupe la lecture sur réplica. different_credentials_for_replica vaut 1 si les identifiants diffèrent, sinon 0. En réplication maître-réplica MariaDB, le nom et le mot de passe sont les mêmes des deux côtés. Accordez aussi au primaire le droit d’accéder à l’esclave, via GRANT.
Ce que le drapeau ne fait pas
Activer read_from_replica n’envoie pas toutes les requêtes au réplica. Frappe ne bascule que dans une fonction décorée par @frappe.read_only(). Le reste reste sur le primaire.
Les chemins déjà décorés : les vues liste (frappe.desk.reportview), les compteurs de notification, et l’exécution des rapports (frappe.desk.query_report.run). Les Script Reports et Query Reports tournent donc déjà sur le réplica, sans changement de code.
Pour un point d’API lent qui ne fait que lire :
@frappe.whitelist()
@frappe.read_only()
def get_sales_summary(from_date, to_date):
return frappe.db.sql(
"""
select customer, sum(grand_total) as total
from `tabSales Invoice`
where docstatus = 1 and posting_date between %s and %s
group by customer
""",
(from_date, to_date),
as_dict=True,
)Quand le drapeau est actif, le décorateur ouvre le réplica, le place dans frappe.db pendant la fonction, puis restaure le primaire. S’il est inactif, le décorateur ne fait rien : on peut le laisser sur tous les sites. Les appels imbriqués réutilisent la connexion déjà ouverte. Le comportement est le même en version 15 et 16. Le retard de réplication rend les données un peu en retard : ne décorer que ce qui tolère un léger décalage.
Attention
Pas d’écriture dans une fonction read-only. Un INSERT, un UPDATE ou un save() part vers le réplica et échoue. Pour un petit écrit, par exemple un journal, une fonction à part porte @frappe.write_only(), qui revient au primaire le temps de l’appel.
@frappe.write_only()
def log_report_access(report_name):
frappe.get_doc({"doctype": "Access Log", "report_name": report_name}).insert()Bons candidats : méthodes en liste blanche qui ne lisent, tableaux de bord et portail qui parcourent de grandes tables, exports et agrégats. Les points qui créent, modifient, soumettent ou annulent restent sur le primaire.
