feat: wrap read only mode SQL errors

This commit is contained in:
Ankush Menat 2022-09-07 12:54:46 +05:30
parent 5922c0ea35
commit f96505fae0
5 changed files with 30 additions and 1 deletions

View file

@ -221,6 +221,15 @@ class Database:
elif self.is_timedout(e):
raise frappe.QueryTimeoutError(e) from e
elif self.is_read_only_mode_error(e):
frappe.throw(
_(
"Site is running in read only mode, this action can not be performed right now. Please try again later."
),
title=_("In Read Only Mode"),
exc=frappe.InReadOnlyMode,
)
# TODO: added temporarily
elif self.db_type == "postgres":
traceback.print_stack()

View file

@ -32,6 +32,10 @@ class MariaDBExceptionUtil:
def is_timedout(e: pymysql.Error) -> bool:
return e.args[0] == ER.LOCK_WAIT_TIMEOUT
@staticmethod
def is_read_only_mode_error(e: pymysql.Error) -> bool:
return e.args[0] == 1792
@staticmethod
def is_table_missing(e: pymysql.Error) -> bool:
return e.args[0] == ER.NO_SUCH_TABLE

View file

@ -12,7 +12,7 @@ from psycopg2.errorcodes import (
UNDEFINED_TABLE,
UNIQUE_VIOLATION,
)
from psycopg2.errors import SequenceGeneratorLimitExceeded, SyntaxError
from psycopg2.errors import ReadOnlySqlTransaction, SequenceGeneratorLimitExceeded, SyntaxError
from psycopg2.extensions import ISOLATION_LEVEL_REPEATABLE_READ
import frappe
@ -55,6 +55,10 @@ class PostgresExceptionUtil:
# http://initd.org/psycopg/docs/extensions.html?highlight=datatype#psycopg2.extensions.QueryCanceledError
return isinstance(e, psycopg2.extensions.QueryCanceledError)
@staticmethod
def is_read_only_mode_error(e) -> bool:
return isinstance(e, ReadOnlySqlTransaction)
@staticmethod
def is_syntax_error(e):
return isinstance(e, SyntaxError)

View file

@ -236,6 +236,10 @@ class QueryDeadlockError(Exception):
pass
class InReadOnlyMode(ValidationError):
http_status_code = 503 # temporarily not available
class TooManyWritesError(Exception):
pass

View file

@ -460,6 +460,14 @@ class TestDB(FrappeTestCase):
# recover transaction to continue other tests
raise Exception
def test_read_only_errors(self):
frappe.db.rollback()
frappe.db.begin(read_only=True)
self.addCleanup(frappe.db.rollback)
with self.assertRaises(frappe.InReadOnlyMode):
frappe.db.set_value("User", "Administrator", "full_name", "Haxor")
def test_exists(self):
dt, dn = "User", "Administrator"
self.assertEqual(frappe.db.exists(dt, dn, cache=True), dn)