MetiMiester commited on
Commit
fe90c54
·
verified ·
1 Parent(s): 8a1e549

Update src/utils/sqlite_retry.py

Browse files
Files changed (1) hide show
  1. src/utils/sqlite_retry.py +33 -67
src/utils/sqlite_retry.py CHANGED
@@ -1,67 +1,33 @@
1
- from datetime import datetime, timedelta
2
- import pytz
3
-
4
- # Hotel timezone
5
- OMAN_TZ = pytz.timezone("Asia/Muscat")
6
-
7
-
8
- # -------------------------------------------------
9
- # Core time helpers
10
- # -------------------------------------------------
11
-
12
- def utc_now_iso() -> str:
13
- """
14
- Returns current UTC time in ISO-8601 format.
15
- Used for all audit-safe timestamps.
16
- """
17
- return datetime.utcnow().replace(microsecond=0).isoformat() + "Z"
18
-
19
-
20
- def muscat_now() -> datetime:
21
- """
22
- Returns current time in Asia/Muscat timezone.
23
- """
24
- return datetime.now(OMAN_TZ)
25
-
26
-
27
- # Backward-compatible alias
28
- local_now = muscat_now
29
-
30
-
31
- def local_date_str() -> str:
32
- """
33
- Returns local date (Asia/Muscat) as YYYY-MM-DD.
34
- """
35
- return muscat_now().strftime("%Y-%m-%d")
36
-
37
-
38
- # -------------------------------------------------
39
- # Business day & closing logic
40
- # -------------------------------------------------
41
-
42
- def business_day_for_close(now: datetime | None = None) -> str:
43
- """
44
- Business day closes at 06:00 Asia/Muscat.
45
-
46
- - Before 06:00 → business day = yesterday
47
- - After 06:00 → business day = today
48
- """
49
- if now is None:
50
- now = muscat_now()
51
-
52
- if now.hour < 6:
53
- return (now.date() - timedelta(days=1)).isoformat()
54
- return now.date().isoformat()
55
-
56
-
57
- # Backward-compatible alias
58
- business_date_for_closing = business_day_for_close
59
-
60
-
61
- def should_auto_close(now: datetime | None = None) -> bool:
62
- """
63
- Returns True if auto-closing logic should run.
64
- """
65
- if now is None:
66
- now = muscat_now()
67
- return now.hour >= 6
 
1
+ import sqlite3
2
+ import time
3
+ from typing import Callable, TypeVar
4
+
5
+ T = TypeVar("T")
6
+
7
+
8
+ def run_tx(
9
+ conn: sqlite3.Connection,
10
+ fn: Callable[[sqlite3.Connection], T],
11
+ retries: int = 5,
12
+ delay: float = 0.2,
13
+ ) -> T:
14
+ """
15
+ Runs a SQLite transaction with retry logic.
16
+ Handles 'database is locked' errors safely.
17
+ """
18
+ last_exc = None
19
+
20
+ for attempt in range(retries):
21
+ try:
22
+ result = fn(conn)
23
+ conn.commit()
24
+ return result
25
+ except sqlite3.OperationalError as e:
26
+ conn.rollback()
27
+ last_exc = e
28
+ if "locked" in str(e).lower():
29
+ time.sleep(delay * (attempt + 1))
30
+ continue
31
+ raise
32
+
33
+ raise last_exc