Repair official collection and retire exhausted material tasks
Development CI / check-and-build (push) Successful in 2m59s
GitHub Git mirror / mirror (push) Successful in 6s
Development CI / deploy-development (push) Successful in 5s

This commit is contained in:
eezd committed 2026-11-05 13:30:05 +08:00
1 parent d5d350b7ec
commit d0c2beb9b3
23 files changed
+399 -35

No files matched your search

@@ -0,0 +1,51 @@
"""本次采集修复初始化:默认只读,--execute 幂等建立一次新预算。运行前停止 crawler。"""
import argparse
import asyncio
import copy
import json
from datetime import UTC, datetime
from sqlalchemy import select, text
from alphapulse.core.db import SessionLocal, engine
from alphapulse.models import Source
REPAIR = 'collection-repair-20261105-v1'
CODES = ('sec', 'doj', 'congress')
async def run(execute=False):
output = []
async with SessionLocal() as session:
if not execute:
await session.execute(text('SET TRANSACTION READ ONLY'))
query = select(Source).where(Source.code.in_(CODES)).order_by(Source.code)
if execute:
query = query.with_for_update()
for source in await session.scalars(query):
cursor = copy.deepcopy(source.history_cursor or {})
if cursor.get('collection_repair') == REPAIR:
output.append({'source': source.code, 'already_initialized': True})
continue
affected = []
for key in ('document_retries', 'attachment_retries', 'bill_retries'):
for url, entry in cursor.get(key, {}).items():
affected.append({'kind': key, 'url': url, 'previous_attempts': entry['attempts']})
entry['repair_previous'] = {k: v for k, v in entry.items() if k != 'document'}
entry['attempts'] = 0
entry['next_at'] = datetime.now(UTC).timestamp()
entry.pop('retired_at', None)
cursor['collection_repair'] = REPAIR
if execute:
source.history_cursor = cursor
output.append({'source': source.code, 'items': affected})
if execute:
await session.commit()
await engine.dispose()
return {'mode': 'execute' if execute else 'dry-run', 'sources': output}
if __name__ == '__main__':
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--execute', action='store_true')
print(json.dumps(asyncio.run(run(parser.parse_args().execute)), ensure_ascii=False))