mirror of
https://git.sdf.org/tamservo/robottas.git
synced 2025-11-08 07:03:47 -05:00
Added file locking to avoid db contention
This commit is contained in:
@@ -7,6 +7,8 @@ import time
|
|||||||
import sqlite3
|
import sqlite3
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
from contextlib import closing
|
||||||
|
from filelock import Timeout, FileLock
|
||||||
from fastf1.signalr_aio import Connection
|
from fastf1.signalr_aio import Connection
|
||||||
|
|
||||||
import fastf1
|
import fastf1
|
||||||
@@ -85,7 +87,8 @@ class SignalRClient:
|
|||||||
"SessionData", "LapCount"]
|
"SessionData", "LapCount"]
|
||||||
|
|
||||||
self.debug = debug
|
self.debug = debug
|
||||||
self._db_is_open = False
|
self.messages_db = 'messages.db'
|
||||||
|
self.messages_lock = FileLock('messages.lock')
|
||||||
self.filename = filename
|
self.filename = filename
|
||||||
self.filemode = filemode
|
self.filemode = filemode
|
||||||
self.timeout = timeout
|
self.timeout = timeout
|
||||||
@@ -97,6 +100,7 @@ class SignalRClient:
|
|||||||
stream=sys.stderr
|
stream=sys.stderr
|
||||||
)
|
)
|
||||||
self.logger = logging.getLogger('SignalR')
|
self.logger = logging.getLogger('SignalR')
|
||||||
|
self.logger.warning("Created logger for SignalR")
|
||||||
else:
|
else:
|
||||||
self.logger = logger
|
self.logger = logger
|
||||||
|
|
||||||
@@ -104,23 +108,15 @@ class SignalRClient:
|
|||||||
self._t_last_message = None
|
self._t_last_message = None
|
||||||
|
|
||||||
def _to_file(self, msg):
|
def _to_file(self, msg):
|
||||||
"""
|
|
||||||
self._output_file.write(msg + '\n')
|
|
||||||
self._output_file.flush()
|
|
||||||
"""
|
|
||||||
#print(msg)
|
|
||||||
con = sqlite3.connect('messages.db')
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with con:
|
with self.messages_lock:
|
||||||
self._db_is_open = True
|
with closing(sqlite3.connect(self.messages_db)) as con:
|
||||||
con.execute("insert into messages (message) values(?)", (msg,))
|
with closing(con.cursor()) as cur:
|
||||||
con.close()
|
#self.logger.warning("about to log: " + msg)
|
||||||
self.db_is_open = False
|
cur.execute("insert into messages (message) values(?)", (msg,))
|
||||||
|
con.commit()
|
||||||
except:
|
except:
|
||||||
if con is not None:
|
print(f'Error writing message to db.')
|
||||||
con.close()
|
|
||||||
self._db_is_open = False
|
|
||||||
|
|
||||||
async def _on_do_nothing(self, msg):
|
async def _on_do_nothing(self, msg):
|
||||||
# just do nothing with the message; intended for debug mode where some
|
# just do nothing with the message; intended for debug mode where some
|
||||||
@@ -196,8 +192,6 @@ class SignalRClient:
|
|||||||
await asyncio.gather(asyncio.ensure_future(self._supervise()),
|
await asyncio.gather(asyncio.ensure_future(self._supervise()),
|
||||||
asyncio.ensure_future(self._run()))
|
asyncio.ensure_future(self._run()))
|
||||||
#self._output_file.close()
|
#self._output_file.close()
|
||||||
while(self._db_is_open):
|
|
||||||
asyncio.sleep(1)
|
|
||||||
self.logger.warning("Exiting...")
|
self.logger.warning("Exiting...")
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
|
|||||||
65
robottas.py
65
robottas.py
@@ -17,9 +17,10 @@ from subprocess import Popen
|
|||||||
import time
|
import time
|
||||||
import discord
|
import discord
|
||||||
|
|
||||||
|
from contextlib import closing
|
||||||
|
from filelock import Timeout, FileLock
|
||||||
from discord.ext import commands, tasks
|
from discord.ext import commands, tasks
|
||||||
|
|
||||||
logging.basicConfig(stream=sys.stderr, level=logging.DEBUG)
|
|
||||||
|
|
||||||
|
|
||||||
class Robottas(commands.Bot):
|
class Robottas(commands.Bot):
|
||||||
@@ -29,15 +30,16 @@ class Robottas(commands.Bot):
|
|||||||
# the Livetiming client.
|
# the Livetiming client.
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def convert_message(raw):
|
def convert_message(raw, logger):
|
||||||
data = raw.replace("'", '"') \
|
data = raw.replace("'", '"') \
|
||||||
.replace('True', 'true') \
|
.replace('True', 'true') \
|
||||||
.replace('False', 'false')
|
.replace('False', 'false')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
data = json.loads(data)
|
data = json.loads(data)
|
||||||
|
logger.warn(f"convert_message returning: {data}")
|
||||||
return data
|
return data
|
||||||
except json.JSONDecodeError:
|
except json.JSONDecodeError:
|
||||||
|
logger.warn("json decode error for")
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
# End section adapted from FastF1
|
# End section adapted from FastF1
|
||||||
@@ -380,6 +382,7 @@ class Robottas(commands.Bot):
|
|||||||
await self.print_driver_range(ctx, 10, 20)
|
await self.print_driver_range(ctx, 10, 20)
|
||||||
|
|
||||||
def load_initial(self, message):
|
def load_initial(self, message):
|
||||||
|
#self.logger.warning("in load_initial")
|
||||||
# Load podium data
|
# Load podium data
|
||||||
if 'R' in message.keys():
|
if 'R' in message.keys():
|
||||||
if 'TopThree' in message['R'].keys():
|
if 'TopThree' in message['R'].keys():
|
||||||
@@ -392,6 +395,7 @@ class Robottas(commands.Bot):
|
|||||||
|
|
||||||
# Load driver list
|
# Load driver list
|
||||||
if 'DriverList' in message['R'].keys():
|
if 'DriverList' in message['R'].keys():
|
||||||
|
#self.logger.warning("loading DriverList")
|
||||||
for driver_num in message['R']['DriverList'].keys():
|
for driver_num in message['R']['DriverList'].keys():
|
||||||
if driver_num == '_kf':
|
if driver_num == '_kf':
|
||||||
continue
|
continue
|
||||||
@@ -429,7 +433,7 @@ class Robottas(commands.Bot):
|
|||||||
async def process_message(self, message):
|
async def process_message(self, message):
|
||||||
try:
|
try:
|
||||||
if isinstance(message, collections.abc.Sequence):
|
if isinstance(message, collections.abc.Sequence):
|
||||||
logging.debug(message)
|
#self.logger.warning(f"in process_message {message}")
|
||||||
|
|
||||||
if message[0] == 'Heartbeat':
|
if message[0] == 'Heartbeat':
|
||||||
return
|
return
|
||||||
@@ -466,34 +470,34 @@ class Robottas(commands.Bot):
|
|||||||
def get_messages_from_db(self):
|
def get_messages_from_db(self):
|
||||||
try:
|
try:
|
||||||
messages = []
|
messages = []
|
||||||
con = sqlite3.connect(self.dbfile)
|
with self.messages_lock:
|
||||||
cur = con.cursor()
|
with closing(sqlite3.connect(self.dbfile)) as con:
|
||||||
cur2 = con.cursor()
|
with closing(con.cursor()) as cur:
|
||||||
for row in cur.execute('select id, message from messages order by id asc'):
|
with closing(con.cursor()) as cur2:
|
||||||
messages.append(self.convert_message(row[1]))
|
for row in cur.execute('select id, message from messages order by id asc'):
|
||||||
|
messages.append(self.convert_message(row[1], self.logger))
|
||||||
|
self.logger.warn(f"get_messages_from_db: {row[1]}")
|
||||||
|
|
||||||
# Now that we have the message, delete this row from the dbfile
|
# Now that we have the message, delete this row from the dbfile
|
||||||
cur2.execute(f"delete from messages where id = {row[0]}")
|
cur2.execute(f"delete from messages where id = {row[0]}")
|
||||||
|
|
||||||
con.commit()
|
con.commit()
|
||||||
cur.close()
|
|
||||||
cur2.close()
|
|
||||||
con.close()
|
|
||||||
|
|
||||||
return messages
|
return messages
|
||||||
except:
|
except:
|
||||||
|
self.logger.warning(f"Error retrieving messages.")
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
|
||||||
def clear_messages_from_db(self):
|
def clear_messages_from_db(self):
|
||||||
try:
|
try:
|
||||||
con = sqlite3.connect(self.dbfile)
|
with self.messages_lock:
|
||||||
cur = con.cursor()
|
with closing(sqlite3.connect(self.dbfile)) as con:
|
||||||
cur.execute('delete from messges')
|
with closing(con.cursor()) as cur:
|
||||||
con.commit()
|
cur.execute('delete from messages')
|
||||||
cur.close()
|
con.commit()
|
||||||
con.close()
|
except Exception as e:
|
||||||
except:
|
self.logger.warning(f"error in clear_messages_from_db: {e}")
|
||||||
pass
|
|
||||||
|
|
||||||
async def _race_report(self, ctx):
|
async def _race_report(self, ctx):
|
||||||
self.clear_messages_from_db()
|
self.clear_messages_from_db()
|
||||||
@@ -522,14 +526,16 @@ class Robottas(commands.Bot):
|
|||||||
while self.is_reporting:
|
while self.is_reporting:
|
||||||
# Do processing
|
# Do processing
|
||||||
|
|
||||||
|
#self.logger.warning("in is_reporting")
|
||||||
|
|
||||||
# process any new messages in the db
|
# process any new messages in the db
|
||||||
messages = self.get_messages_from_db()
|
messages = self.get_messages_from_db()
|
||||||
try:
|
try:
|
||||||
for message in messages:
|
for message in messages:
|
||||||
|
#self.logger.warning(f"processing message: {message}")
|
||||||
await self.process_message(message)
|
await self.process_message(message)
|
||||||
logging.debug(message)
|
await asyncio.sleep(2)
|
||||||
|
|
||||||
await asyncio.sleep(3)
|
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -632,7 +638,7 @@ class Robottas(commands.Bot):
|
|||||||
self.collector_proc.kill()
|
self.collector_proc.kill()
|
||||||
self.clear_messages_from_db()
|
self.clear_messages_from_db()
|
||||||
except:
|
except:
|
||||||
pass
|
self.logger.warn("error in stop_collect.")
|
||||||
|
|
||||||
def decode_watched(self, w):
|
def decode_watched(self, w):
|
||||||
if w == 0:
|
if w == 0:
|
||||||
@@ -858,6 +864,13 @@ class Robottas(commands.Bot):
|
|||||||
# Set debug or not
|
# Set debug or not
|
||||||
self.debug = True
|
self.debug = True
|
||||||
|
|
||||||
|
self.messages_lock = FileLock('messages.lock')
|
||||||
|
|
||||||
|
#configure logging
|
||||||
|
logging.basicConfig(stream=sys.stderr, \
|
||||||
|
format="%(asctime)s - %(levelname)s: %(message)s")
|
||||||
|
self.logger = logging.getLogger('robottas')
|
||||||
|
|
||||||
self.bingo = Bingo()
|
self.bingo = Bingo()
|
||||||
|
|
||||||
# Discord authentication token
|
# Discord authentication token
|
||||||
|
|||||||
Reference in New Issue
Block a user