Skip to content

Commit d0d78fb

Browse files
committed
improve corrupted files handling
1 parent a8937e7 commit d0d78fb

1 file changed

Lines changed: 47 additions & 6 deletions

File tree

modules/helper/state.py

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,68 @@
1+
import os
12
import pickle
3+
import tempfile
24
from datetime import datetime, timezone
35

46

57
# store temporary values. unreadable and uneditable.
68
class AppState:
79
interval = 20 # [s]
810

9-
last_write_time = datetime.now(timezone.utc)
1011
pickle_file = "state.pickle"
11-
values = None
1212

1313
def __init__(self):
14+
self.last_write_time = datetime.now(timezone.utc)
15+
self.values = {}
16+
1417
try:
1518
with open(self.pickle_file, "rb") as f:
1619
self.values = pickle.load(f)
1720
except FileNotFoundError:
1821
self.values = {}
22+
except (
23+
EOFError,
24+
OSError,
25+
pickle.UnpicklingError,
26+
AttributeError,
27+
ValueError,
28+
TypeError,
29+
) as exc:
30+
self.values = {}
31+
self._backup_corrupted_state_file(exc)
1932

2033
def write(self):
21-
with open(self.pickle_file, "wb") as f:
22-
pickle.dump(self.values, f)
34+
directory = os.path.dirname(self.pickle_file) or "."
35+
fd, tmp_path = tempfile.mkstemp(
36+
prefix=".state.",
37+
suffix=".tmp",
38+
dir=directory,
39+
)
40+
try:
41+
with os.fdopen(fd, "wb") as f:
42+
pickle.dump(self.values, f)
43+
f.flush()
44+
os.fsync(f.fileno())
45+
os.replace(tmp_path, self.pickle_file)
46+
finally:
47+
if os.path.exists(tmp_path):
48+
os.remove(tmp_path)
49+
50+
def _backup_corrupted_state_file(self, exc):
51+
if not os.path.exists(self.pickle_file):
52+
return
53+
54+
timestamp = datetime.now(timezone.utc).strftime("%Y%m%d_%H%M%S")
55+
backup_path = f"{self.pickle_file}.corrupt-{timestamp}"
56+
suffix = 1
57+
while os.path.exists(backup_path):
58+
backup_path = f"{self.pickle_file}.corrupt-{timestamp}-{suffix}"
59+
suffix += 1
60+
61+
try:
62+
os.replace(self.pickle_file, backup_path)
63+
except OSError as backup_exc:
64+
return
65+
2366

2467
def set_value(self, key, value, force_apply=False):
2568
self.values[key] = value
@@ -81,5 +124,3 @@ def delete(self):
81124
s.write()
82125

83126
print(s.values)
84-
85-

0 commit comments

Comments
 (0)