Initial commit.
This commit is contained in:
commit
628e5c3823
26 changed files with 3478 additions and 0 deletions
53
ocado_grocy/enrichment_retry.py
Normal file
53
ocado_grocy/enrichment_retry.py
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
"""Durable product-level retries, independent of completed stock orders."""
|
||||
import json
|
||||
import sqlite3
|
||||
|
||||
|
||||
class RetryQueue:
|
||||
def __init__(self, state, server):
|
||||
self.server = server
|
||||
self.db = sqlite3.connect(state)
|
||||
with self.db:
|
||||
self.db.execute('''CREATE TABLE IF NOT EXISTS enrichment_retries (
|
||||
server TEXT, stage TEXT, product_id INTEGER, error TEXT,
|
||||
PRIMARY KEY(server,stage,product_id))''')
|
||||
self.db.execute('CREATE TABLE IF NOT EXISTS enrichment_retry_migrations (server TEXT PRIMARY KEY)')
|
||||
|
||||
def start(self, stage, products):
|
||||
self.results(stage, [{'product_id':p['id'], 'status':'error', 'error':'Interrupted enrichment'} for p in products])
|
||||
|
||||
def results(self, stage, rows):
|
||||
with self.db:
|
||||
for row in rows:
|
||||
key = (self.server,stage,int(row['product_id']))
|
||||
if row['status'] == 'error':
|
||||
self.db.execute('INSERT OR REPLACE INTO enrichment_retries VALUES (?,?,?,?)', (*key,row.get('error','Enrichment failed')))
|
||||
else:
|
||||
self.db.execute('DELETE FROM enrichment_retries WHERE server=? AND stage=? AND product_id=?',key)
|
||||
|
||||
def pending(self, stage):
|
||||
return {r[0] for r in self.db.execute('SELECT product_id FROM enrichment_retries WHERE server=? AND stage=?',(self.server,stage))}
|
||||
|
||||
def migrate_reports(self, archive, allowed_ids):
|
||||
"""Import old errors once; newer successful reports supersede old failures."""
|
||||
if self.db.execute('SELECT 1 FROM enrichment_retry_migrations WHERE server=?',(self.server,)).fetchone():
|
||||
return
|
||||
events = []
|
||||
for path in (archive/'enrichment').glob('*/summary.json'):
|
||||
summary = json.loads(path.read_text())
|
||||
if summary.get('server',self.server) != self.server:
|
||||
continue
|
||||
for stage in ('images','openfoodfacts'):
|
||||
report_path = path.parent / f'{stage}.json'
|
||||
if report_path.exists():
|
||||
data = json.loads(report_path.read_text())
|
||||
events.append((report_path.stat().st_mtime,stage,data.get('products',[])))
|
||||
elif any(error.lower().startswith('images:' if stage=='images' else 'open food facts:') for error in summary.get('errors',[])):
|
||||
events.append((path.stat().st_mtime,stage,[{'product_id':pid,'status':'error','error':'Previous enrichment failed'} for pid in summary.get('product_ids',[])]))
|
||||
for _,stage,rows in sorted(events,key=lambda event:event[0]):
|
||||
self.results(stage,[r for r in rows if int(r['product_id']) in allowed_ids])
|
||||
with self.db:
|
||||
self.db.execute('INSERT INTO enrichment_retry_migrations VALUES (?)',(self.server,))
|
||||
|
||||
def close(self):
|
||||
self.db.close()
|
||||
Loading…
Add table
Add a link
Reference in a new issue