this repo has no description

feat(feedgen): do a better job of cleaning up on SIGTERM and SIGINT

Changed files
+44 -5
feeds
+7
feed_manager.py
···
for feed in self.feeds.values():
feed.commit_changes()
+
def stop_all(self):
+
for feed in self.feeds.values():
+
try:
+
feed.stop_db_worker()
+
except AttributeError:
+
pass
+
feed_manager = FeedManager()
feed_manager.register(RapidFireFeed)
feed_manager.register(PopularFeed)
+26 -1
feedgen.py
···
from io import BytesIO
import json
import logging
+
import signal
from atproto import CAR
import dag_cbor
···
logging.getLogger('').setLevel(logging.WARNING)
logging.getLogger('feeds').setLevel(logging.DEBUG)
logging.getLogger('firehose').setLevel(logging.DEBUG)
+
logging.getLogger('feedgen').setLevel(logging.DEBUG)
+
+
logger = logging.getLogger('feedgen')
async def firehose_events():
relay_url = 'ws://localhost:6008/subscribe'
···
if event_count % 2500 == 0:
feed_manager.commit_changes()
+
async def shutdown(signal, loop):
+
logger.info(f'received exit signal {signal.name}')
+
feed_manager.stop_all()
+
tasks = [t for t in asyncio.all_tasks() if t is not asyncio.current_task()]
+
[task.cancel() for task in tasks]
+
logger.info(f'cancelling {len(tasks)} outstanding tasks')
+
await asyncio.gather(*tasks, return_exceptions=True)
+
loop.stop()
+
if __name__ == '__main__':
-
asyncio.run(main())
+
loop = asyncio.get_event_loop()
+
catch_signals = (signal.SIGTERM, signal.SIGINT)
+
for sig in catch_signals:
+
loop.add_signal_handler(
+
sig,
+
lambda s=sig: asyncio.create_task(shutdown(s, loop))
+
)
+
+
try:
+
loop.create_task(main())
+
loop.run_forever()
+
finally:
+
loop.close()
+11 -4
feeds/mostliked.py
···
self.changes = 0
def run(self):
-
while not self.stop_signal:
+
while True:
task = self.task_queue.get(block=True)
if task == 'STOP':
-
self.stop_signal = True
+
self.logger.debug('received STOP, breaking now')
+
break
elif task == 'COMMIT':
self.logger.debug(f'committing {self.changes} changes')
if self.db_cnx.in_transaction:
···
self.db_cnx.execute(sql, bindings)
self.changes += self.db_cnx.changes()
self.task_queue.task_done()
+
+
self.logger.debug('closing database connection')
self.db_cnx.close()
def stop(self):
···
self.drafts = ExpiringDict(max_len=50_000, max_age_seconds=5*60)
self.db_writes = queue.Queue()
-
db_worker = DatabaseWorker('mostliked', 'db/mostliked.db', self.db_writes)
-
db_worker.start()
+
self.db_worker = DatabaseWorker('mostliked', 'db/mostliked.db', self.db_writes)
+
self.db_worker.start()
+
+
def stop_db_worker(self):
+
self.logger.debug('sending STOP')
+
self.db_writes.put('STOP')
def process_commit(self, commit):
if commit['opType'] != 'c':