inital commit
This commit is contained in:
71
server/app/mailer/commands/send_queued_jobs.py
Normal file
71
server/app/mailer/commands/send_queued_jobs.py
Normal file
@@ -0,0 +1,71 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
from time import sleep
|
||||
|
||||
from app.db.bootstrap import create_all_tables
|
||||
from app.db.models import CampaignJob, JobQueueStatus, JobSendStatus
|
||||
from app.db.session import SessionLocal
|
||||
from app.mailer.sending.jobs import append_sent_for_job, send_campaign_job
|
||||
from app.security.api_keys import authenticate_api_key
|
||||
from app.settings import settings
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser(description="Process queued campaign jobs directly, without a Celery worker.")
|
||||
parser.add_argument("--campaign-id", required=True)
|
||||
parser.add_argument("--api-key", default=settings.dev_bootstrap_api_key)
|
||||
parser.add_argument("--limit", type=int, default=0, help="Maximum jobs to process; 0 means all queued jobs")
|
||||
parser.add_argument("--dry-run", action="store_true", help="Validate/send path without SMTP delivery or status mutation to SENT")
|
||||
parser.add_argument("--no-rate-limit", action="store_true")
|
||||
parser.add_argument("--append-sent", action="store_true", help="After successful SMTP delivery, immediately run IMAP append-to-Sent in this CLI process")
|
||||
parser.add_argument("--json", action="store_true")
|
||||
args = parser.parse_args()
|
||||
|
||||
create_all_tables()
|
||||
results = []
|
||||
with SessionLocal() as session:
|
||||
api_key = authenticate_api_key(session, args.api_key)
|
||||
if not api_key:
|
||||
raise SystemExit("Invalid API key")
|
||||
query = (
|
||||
session.query(CampaignJob)
|
||||
.filter(
|
||||
CampaignJob.tenant_id == api_key.tenant_id,
|
||||
CampaignJob.campaign_id == args.campaign_id,
|
||||
CampaignJob.queue_status == JobQueueStatus.QUEUED.value,
|
||||
CampaignJob.send_status.in_([JobSendStatus.QUEUED.value, JobSendStatus.FAILED_TEMPORARY.value]),
|
||||
)
|
||||
.order_by(CampaignJob.entry_index.asc())
|
||||
)
|
||||
if args.limit > 0:
|
||||
query = query.limit(args.limit)
|
||||
jobs = query.all()
|
||||
for job in jobs:
|
||||
try:
|
||||
result = send_campaign_job(session, job_id=job.id, dry_run=args.dry_run, use_rate_limit=not args.no_rate_limit)
|
||||
result_dict = result.as_dict()
|
||||
if args.append_sent and result.status == "sent":
|
||||
append_result = append_sent_for_job(session, job_id=job.id, dry_run=args.dry_run)
|
||||
result_dict["imap_append"] = append_result.as_dict()
|
||||
results.append(result_dict)
|
||||
if not args.json:
|
||||
line = f"{job.entry_index}: {result.status} ({job.recipient_email})"
|
||||
if "imap_append" in result_dict:
|
||||
line += f"; IMAP: {result_dict['imap_append']['status']}"
|
||||
print(line)
|
||||
except Exception as exc:
|
||||
results.append({"job_id": job.id, "status": "error", "error": str(exc)})
|
||||
if not args.json:
|
||||
print(f"{job.entry_index}: ERROR {exc} ({job.recipient_email})")
|
||||
# Continue with the next job; individual attempts/statuses are recorded.
|
||||
sleep(0.1)
|
||||
if args.json:
|
||||
print(json.dumps({"processed": len(results), "results": results}, indent=2))
|
||||
elif not jobs:
|
||||
print("No queued jobs found")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user