simo 3.1.4__py3-none-any.whl → 3.1.5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of simo might be problematic. Click here for more details.
- simo/core/db_backend/base.py +60 -6
- {simo-3.1.4.dist-info → simo-3.1.5.dist-info}/METADATA +1 -1
- {simo-3.1.4.dist-info → simo-3.1.5.dist-info}/RECORD +7 -7
- {simo-3.1.4.dist-info → simo-3.1.5.dist-info}/WHEEL +0 -0
- {simo-3.1.4.dist-info → simo-3.1.5.dist-info}/entry_points.txt +0 -0
- {simo-3.1.4.dist-info → simo-3.1.5.dist-info}/licenses/LICENSE.md +0 -0
- {simo-3.1.4.dist-info → simo-3.1.5.dist-info}/top_level.txt +0 -0
simo/core/db_backend/base.py
CHANGED
|
@@ -1,19 +1,73 @@
|
|
|
1
1
|
from django.contrib.gis.db.backends.postgis.base import (
|
|
2
2
|
DatabaseWrapper as PostGisPsycopg2DatabaseWrapper
|
|
3
3
|
)
|
|
4
|
-
|
|
4
|
+
"""Custom PostGIS database wrapper with light self-healing.
|
|
5
|
+
|
|
6
|
+
We retry cursor creation on transient driver-level errors. Previously we
|
|
7
|
+
were catching Django's wrapper exceptions (django.db.utils.InterfaceError/
|
|
8
|
+
OperationalError). However, those are only raised by the outer
|
|
9
|
+
`wrap_database_errors` context. Inside `create_cursor()` the driver
|
|
10
|
+
(`psycopg2`) raises its own exceptions, so our except block never ran and
|
|
11
|
+
connections weren't healed.
|
|
12
|
+
|
|
13
|
+
By catching psycopg2 errors here (in addition to Django's), we ensure
|
|
14
|
+
we can close() and reconnect() this connection when `self.connection`
|
|
15
|
+
is already closed or becomes unusable, avoiding busy error loops in
|
|
16
|
+
MQTT threads and periodic tasks.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from django.db.utils import OperationalError as DjangoOperationalError, InterfaceError as DjangoInterfaceError
|
|
20
|
+
try:
|
|
21
|
+
# Catch driver-level errors where they originate.
|
|
22
|
+
from psycopg2 import OperationalError as PsycopgOperationalError, InterfaceError as PsycopgInterfaceError
|
|
23
|
+
except Exception: # pragma: no cover - very defensive
|
|
24
|
+
PsycopgOperationalError = PsycopgInterfaceError = Exception
|
|
5
25
|
from django.utils.asyncio import async_unsafe
|
|
26
|
+
import time
|
|
27
|
+
import random
|
|
6
28
|
|
|
7
29
|
|
|
8
30
|
class DatabaseWrapper(PostGisPsycopg2DatabaseWrapper):
|
|
9
31
|
@async_unsafe
|
|
10
32
|
def create_cursor(self, name=None):
|
|
33
|
+
"""Create a DB cursor with a single, simple heal-once path.
|
|
34
|
+
|
|
35
|
+
- Fast path: return cursor immediately.
|
|
36
|
+
- On error: if it's a connectivity issue (known exceptions or
|
|
37
|
+
connection.closed set), close + backoff + reconnect, then retry once.
|
|
38
|
+
- Otherwise: re-raise the original exception.
|
|
39
|
+
"""
|
|
11
40
|
try:
|
|
12
41
|
return super().create_cursor(name=name)
|
|
13
|
-
except
|
|
14
|
-
#
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
42
|
+
except Exception as e:
|
|
43
|
+
# Determine if this is a connectivity problem
|
|
44
|
+
is_connectivity_err = isinstance(
|
|
45
|
+
e,
|
|
46
|
+
(
|
|
47
|
+
DjangoInterfaceError,
|
|
48
|
+
DjangoOperationalError,
|
|
49
|
+
PsycopgInterfaceError,
|
|
50
|
+
PsycopgOperationalError,
|
|
51
|
+
),
|
|
52
|
+
)
|
|
53
|
+
if not is_connectivity_err:
|
|
54
|
+
try:
|
|
55
|
+
conn = getattr(self, 'connection', None)
|
|
56
|
+
is_connectivity_err = bool(getattr(conn, 'closed', 0))
|
|
57
|
+
except Exception:
|
|
58
|
+
is_connectivity_err = False
|
|
18
59
|
|
|
60
|
+
if not is_connectivity_err:
|
|
61
|
+
# Not a connection issue; bubble up unchanged
|
|
62
|
+
raise
|
|
19
63
|
|
|
64
|
+
# Heal this very connection and retry once
|
|
65
|
+
try:
|
|
66
|
+
self.close()
|
|
67
|
+
finally:
|
|
68
|
+
try:
|
|
69
|
+
time.sleep(0.05 + random.random() * 0.15) # 50–200 ms
|
|
70
|
+
except Exception:
|
|
71
|
+
pass
|
|
72
|
+
self.connect()
|
|
73
|
+
return super().create_cursor(name=name)
|
|
@@ -191,7 +191,7 @@ simo/core/__pycache__/views.cpython-38.pyc,sha256=kYKvEcyKicdkTcN0iEJ4pT101-KHiZ
|
|
|
191
191
|
simo/core/__pycache__/widgets.cpython-312.pyc,sha256=f_AiYFfA7Wl4Wm9FqUOlluSGLAN_nkLyDUsKpkScsXg,4447
|
|
192
192
|
simo/core/__pycache__/widgets.cpython-38.pyc,sha256=sR0ZeHCHrhnNDBJuRrxp3zUsfBp0xrtF0xrK2TkQv1o,3520
|
|
193
193
|
simo/core/db_backend/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
194
|
-
simo/core/db_backend/base.py,sha256=
|
|
194
|
+
simo/core/db_backend/base.py,sha256=fGagw119bvP3Ns3NFvIDlrlNSa9-LLt2HMuIjnB9h9g,2933
|
|
195
195
|
simo/core/db_backend/__pycache__/__init__.cpython-312.pyc,sha256=Brq4UBCggJrt590OFV3VmgARJYRK902FnnFFFK_Azng,133
|
|
196
196
|
simo/core/db_backend/__pycache__/__init__.cpython-38.pyc,sha256=sxC6PmFqnwe6RRKzSR7QtUFzRc_aRRR1fffsR3TPLRc,169
|
|
197
197
|
simo/core/db_backend/__pycache__/base.cpython-312.pyc,sha256=ykKrTOC28v2cl0C--bqeLEaydHS5CG1RFGL0lon53HU,1135
|
|
@@ -11034,9 +11034,9 @@ simo/users/templates/invitations/expired_msg.html,sha256=47DEQpj8HBSa-_TImW-5JCe
|
|
|
11034
11034
|
simo/users/templates/invitations/expired_suggestion.html,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
11035
11035
|
simo/users/templates/invitations/taken_msg.html,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
11036
11036
|
simo/users/templates/invitations/taken_suggestion.html,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
11037
|
-
simo-3.1.
|
|
11038
|
-
simo-3.1.
|
|
11039
|
-
simo-3.1.
|
|
11040
|
-
simo-3.1.
|
|
11041
|
-
simo-3.1.
|
|
11042
|
-
simo-3.1.
|
|
11037
|
+
simo-3.1.5.dist-info/licenses/LICENSE.md,sha256=M7wm1EmMGDtwPRdg7kW4d00h1uAXjKOT3HFScYQMeiE,34916
|
|
11038
|
+
simo-3.1.5.dist-info/METADATA,sha256=hXkJ2qxHLFHebhXd3yRy4Gvj2Bd4Vi2-ulumfeyYcIM,2224
|
|
11039
|
+
simo-3.1.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
11040
|
+
simo-3.1.5.dist-info/entry_points.txt,sha256=S9PwnUYmTSW7681GKDCxUbL0leRJIaRk6fDQIKgbZBA,135
|
|
11041
|
+
simo-3.1.5.dist-info/top_level.txt,sha256=GmS1hrAbpVqn9OWZh6UX82eIOdRLgYA82RG9fe8v4Rs,5
|
|
11042
|
+
simo-3.1.5.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|