Better error handling

This commit is contained in:
Neale Pickett 2022-09-02 17:04:07 -06:00
parent a559e92d3e
commit c15681a51c
5 changed files with 83 additions and 65 deletions

View File

@ -5,6 +5,7 @@ import time
import logging
import re
import os
import shutil
SECOND = 1
MINUTE = 60 * SECOND
@ -154,7 +155,7 @@ def encode(state, directory):
def clean(state, directory):
os.removedirs(directory)
shutil.rmtree(directory)
if __name__ == "__main__":
import pprint

View File

@ -12,30 +12,22 @@ import re
import logging
import dvd
import cd
import traceback
import worker
class Encoder(worker.Worker):
def __init__(self, directory=None):
self.status = {}
self.directory = directory
self.loop_delay = 12
return super().__init__(directory)
def run(self):
while True:
wait = True
self.status = {"type": "encoder", "state": "idle"}
for fn in glob.glob(self.workdir("*", "sucker.json")):
directory = os.path.dirname(fn)
state = self.read_state(directory)
try:
self.encode(directory, state)
except Exception as e:
logging.error("Error encoding %s: %s" % (directory, e))
logging.error(traceback.format_exc())
wait = False
if wait:
time.sleep(12)
def once(self):
wait = True
self.status["type"] = "encoder"
for fn in glob.glob(self.workdir("*", "sucker.json")):
directory = os.path.dirname(fn)
state = self.read_state(directory)
self.encode(directory, state)
def encode(self, directory, state):
self.status["state"] = "encoding"

View File

@ -5,7 +5,6 @@ import subprocess
import time
import re
import fcntl
import traceback
import json
import logging
import slugify
@ -29,58 +28,55 @@ CDS_DATA_2 = 102
CDROM_LOCKDOOR = 0x5329
CDROM_EJECT = 0x5309
SECOND = 1
MINUTE = 60 * SECOND
HOUR = 60 * MINUTE
class Reader(worker.Worker):
def __init__(self, device, directory):
super().__init__(directory)
self.device = device
self.status["type"] = "reader"
self.status["device"] = device
self.complete = 0
self.staleness = 0
self.drive = None
logging.info("Starting reader on %s" % self.device)
def reopen(self):
if (self.staleness > 15) or not self.drive:
if self.drive:
os.close(self.drive)
self.drive = None
try:
self.drive = os.open(self.device, os.O_RDONLY | os.O_NONBLOCK)
logging.debug("Reopened %s" % self.device)
except FileNotFoundError:
pass
self.staleness = 0
else:
if self.drive and (self.staleness < 15):
self.staleness += 1
return True
self.staleness = 0
if self.drive:
os.close(self.drive)
self.drive = None
try:
self.drive = os.open(self.device, os.O_RDONLY | os.O_NONBLOCK)
logging.debug("Reopened %s" % self.device)
return True
except FileNotFoundError:
return False
def run(self):
while True:
self.status["state"] = "idle"
self.reopen()
if not self.drive:
time.sleep(30)
continue
rv = fcntl.ioctl(self.drive, CDROM_DRIVE_STATUS)
if rv == CDS_DISC_OK:
rv = fcntl.ioctl(self.drive, CDROM_DISC_STATUS)
try:
if rv == CDS_AUDIO:
self.handle(False)
elif rv in [CDS_DATA_1, CDS_DATA_2]:
self.handle(True)
else:
logging.info("Can't handle disc type %d" % rv)
except Exception as e:
logging.error("Error in disc handler: %s" % e)
logging.error(traceback.format_exc())
self.eject()
elif rv in (CDS_TRAY_OPEN, CDS_NO_DISC, CDS_DRIVE_NOT_READ):
time.sleep(3)
def once(self):
self.status["type"] = "reader"
self.status["device"] = self.device
if not self.reopen():
time.sleep(10 * SECOND)
return
rv = fcntl.ioctl(self.drive, CDROM_DRIVE_STATUS)
if rv == CDS_DISC_OK:
rv = fcntl.ioctl(self.drive, CDROM_DISC_STATUS)
if rv == CDS_AUDIO:
self.handle(False)
elif rv in [CDS_DATA_1, CDS_DATA_2]:
self.handle(True)
else:
logging.info("CDROM_DRIVE_STATUS: %d (%s)" % (rv, CDS_STR[rv]))
time.sleep(3)
logging.info("Can't handle disc type %d" % rv)
self.eject()
elif rv in (CDS_TRAY_OPEN, CDS_NO_DISC, CDS_DRIVE_NOT_READ):
time.sleep(3 * SECOND)
else:
logging.info("CDROM_DRIVE_STATUS: %d (%s)" % (rv, CDS_STR[rv]))
time.sleep(3 * SECOND)
def eject(self):
for i in range(20):
try:

View File

@ -10,14 +10,20 @@ import reader, encoder, statuser
class HTTPRequestHandler(http.server.SimpleHTTPRequestHandler):
def __init__(self, r, a, s, directory, statuser):
self.statuser = statuser
self.quiet = False
super().__init__(r, a, s, directory=directory)
def log_request(self, code="-", size="-"):
if not self.quiet:
super().log_request(code, size)
def do_GET(self):
if self.path == "/status.json":
return self.get_status()
return super().do_GET()
def get_status(self):
self.quiet = True
self.send_response(200)
self.end_headers()
buf = self.statuser.json().encode("utf-8")

View File

@ -2,17 +2,34 @@ import threading
import os
import json
import logging
import time
import traceback
SECOND = 1
MINUTE = 60 * SECOND
HOUR = 60 * MINUTE
class Worker(threading.Thread):
def __init__(self, directory, **kwargs):
self.directory = directory
self.status = {
"state": "idle",
}
self.loop_delay = 2 * SECOND
self.status = {}
kwargs["daemon"] = True
return super().__init__(**kwargs)
def run(self):
while True:
self.status = {"state": "idle"}
try:
self.once()
except Exception as exc:
self.status["state"] = "error"
for line in traceback.format_exception(exc):
logging.error(line)
time.sleep(30 * SECOND)
time.sleep(self.loop_delay)
def workdir(self, *path):
return os.path.join(self.directory, *path)
@ -25,8 +42,14 @@ class Worker(threading.Thread):
os.rename(newstatefn, statefn)
def read_state(self, subdir):
with open(self.workdir(subdir, "sucker.json")) as f:
return json.load(f)
try:
with open(self.workdir(subdir, "sucker.json")) as f:
return json.load(f)
except FileNotFoundError:
return {}
def clear_state(self, subdir):
os.unlink(self.workdir(subdir, "sucker.json"))
try:
os.unlink(self.workdir(subdir, "sucker.json"))
except FileNotFoundError:
pass