Refactor campaign delivery decision paths
This commit is contained in:
@@ -307,59 +307,40 @@ class _JobReportAggregate:
|
||||
include_recent_failures: bool,
|
||||
) -> None:
|
||||
self.total += 1
|
||||
self._add_statuses(job)
|
||||
self._add_delivery_counts(job, retry_max_attempts=retry_max_attempts)
|
||||
self._add_issues(job)
|
||||
self._add_attachments(job)
|
||||
self._add_recent_failure(job, include_recent_failures=include_recent_failures)
|
||||
|
||||
def _add_statuses(self, job: CampaignJob) -> None:
|
||||
self.build[job.build_status or "unknown"] += 1
|
||||
self.validation[job.validation_status or "unknown"] += 1
|
||||
self.queue[job.queue_status or "unknown"] += 1
|
||||
self.send[job.send_status or "unknown"] += 1
|
||||
self.postbox[job.postbox_status or "unknown"] += 1
|
||||
self.imap[job.imap_status or "unknown"] += 1
|
||||
|
||||
def _add_delivery_counts(self, job: CampaignJob, *, retry_max_attempts: int | None) -> None:
|
||||
if job.send_status in {"queued", "claimed", "sending"}:
|
||||
self.pending += 1
|
||||
if (
|
||||
job.validation_status in {"ready", "warning"}
|
||||
and job.build_status == "built"
|
||||
):
|
||||
if _job_is_queueable(job):
|
||||
self.queueable += 1
|
||||
if (
|
||||
job.attempt_count == 0
|
||||
and job.postbox_attempt_count == 0
|
||||
and job.send_status in {"not_queued", "cancelled"}
|
||||
and job.validation_status in {"ready", "warning"}
|
||||
and job.build_status == "built"
|
||||
):
|
||||
if _job_is_queueable_unattempted(job):
|
||||
self.queueable_unattempted += 1
|
||||
if (
|
||||
job.send_status in {"failed_temporary", "partially_accepted"}
|
||||
and (
|
||||
retry_max_attempts is None
|
||||
or job.attempt_count < retry_max_attempts
|
||||
)
|
||||
):
|
||||
if _job_is_retryable(job, retry_max_attempts=retry_max_attempts):
|
||||
self.retryable += 1
|
||||
if job.send_status not in {
|
||||
"skipped",
|
||||
"smtp_accepted",
|
||||
"postbox_accepted",
|
||||
"delivered",
|
||||
"partially_accepted",
|
||||
"sent",
|
||||
"outcome_unknown",
|
||||
"claimed",
|
||||
"sending",
|
||||
"cancelled",
|
||||
}:
|
||||
if _job_is_cancellable(job):
|
||||
self.cancellable += 1
|
||||
if _job_needs_attention(job):
|
||||
self.needs_attention += 1
|
||||
self._add_issues(job)
|
||||
self._add_attachments(job)
|
||||
if include_recent_failures and _job_is_recent_failure(job):
|
||||
self.recent_failures.append(job)
|
||||
self.recent_failures.sort(
|
||||
key=lambda item: item.updated_at or item.created_at,
|
||||
reverse=True,
|
||||
)
|
||||
del self.recent_failures[20:]
|
||||
|
||||
def _add_recent_failure(self, job: CampaignJob, *, include_recent_failures: bool) -> None:
|
||||
if not include_recent_failures or not _job_is_recent_failure(job):
|
||||
return
|
||||
self.recent_failures.append(job)
|
||||
self.recent_failures.sort(key=lambda item: item.updated_at or item.created_at, reverse=True)
|
||||
del self.recent_failures[20:]
|
||||
|
||||
def _add_issues(self, job: CampaignJob) -> None:
|
||||
for issue in job.issues_snapshot or []:
|
||||
@@ -391,6 +372,42 @@ class _JobReportAggregate:
|
||||
self.attachment_ambiguous += 1
|
||||
|
||||
|
||||
NON_CANCELLABLE_SEND_STATUSES = {
|
||||
"skipped",
|
||||
"smtp_accepted",
|
||||
"postbox_accepted",
|
||||
"delivered",
|
||||
"partially_accepted",
|
||||
"sent",
|
||||
"outcome_unknown",
|
||||
"claimed",
|
||||
"sending",
|
||||
"cancelled",
|
||||
}
|
||||
|
||||
|
||||
def _job_is_queueable(job: CampaignJob) -> bool:
|
||||
return job.validation_status in {"ready", "warning"} and job.build_status == "built"
|
||||
|
||||
|
||||
def _job_is_queueable_unattempted(job: CampaignJob) -> bool:
|
||||
return (
|
||||
job.attempt_count == 0
|
||||
and job.postbox_attempt_count == 0
|
||||
and job.send_status in {"not_queued", "cancelled"}
|
||||
and _job_is_queueable(job)
|
||||
)
|
||||
|
||||
|
||||
def _job_is_retryable(job: CampaignJob, *, retry_max_attempts: int | None) -> bool:
|
||||
attempts_available = retry_max_attempts is None or job.attempt_count < retry_max_attempts
|
||||
return job.send_status in {"failed_temporary", "partially_accepted"} and attempts_available
|
||||
|
||||
|
||||
def _job_is_cancellable(job: CampaignJob) -> bool:
|
||||
return job.send_status not in NON_CANCELLABLE_SEND_STATUSES
|
||||
|
||||
|
||||
def _job_needs_attention(job: CampaignJob) -> bool:
|
||||
return (
|
||||
job.validation_status in {"needs_review", "blocked"}
|
||||
@@ -577,31 +594,48 @@ def _job_evidence_row(
|
||||
"campaign_id": job.campaign_id,
|
||||
"campaign_version_id": job.campaign_version_id,
|
||||
"message_id_header": job.message_id_header,
|
||||
"from": _address_summary(recipients.get("from")),
|
||||
"to": _address_summary(recipients.get("to")),
|
||||
"cc": _address_summary(recipients.get("cc")),
|
||||
"bcc": _address_summary(recipients.get("bcc")),
|
||||
"reply_to": _address_summary(recipients.get("reply_to")),
|
||||
"postbox_targets": "; ".join(
|
||||
str(target.get("address") or target.get("name") or target.get("postbox_id") or "")
|
||||
for target in (
|
||||
getattr(job, "resolved_postbox_targets", None) or []
|
||||
)
|
||||
if isinstance(target, dict)
|
||||
),
|
||||
**_job_evidence_addresses(recipients),
|
||||
"postbox_targets": _job_postbox_target_summary(job),
|
||||
"attachment_names": _attachment_names(job.resolved_attachments),
|
||||
**_job_attempt_evidence(latest_smtp=latest_smtp, latest_imap=latest_imap),
|
||||
})
|
||||
return row
|
||||
|
||||
|
||||
def _job_evidence_addresses(recipients: dict[str, Any]) -> dict[str, str]:
|
||||
return {key: _address_summary(recipients.get(key)) for key in ("from", "to", "cc", "bcc", "reply_to")}
|
||||
|
||||
|
||||
def _job_postbox_target_summary(job: CampaignJob) -> str:
|
||||
targets = getattr(job, "resolved_postbox_targets", None) or []
|
||||
return "; ".join(
|
||||
str(target.get("address") or target.get("name") or target.get("postbox_id") or "")
|
||||
for target in targets
|
||||
if isinstance(target, dict)
|
||||
)
|
||||
|
||||
|
||||
def _iso_timestamp(value: datetime | None) -> str | None:
|
||||
return value.isoformat() if value else None
|
||||
|
||||
|
||||
def _job_attempt_evidence(
|
||||
*,
|
||||
latest_smtp: SendAttempt | None,
|
||||
latest_imap: ImapAppendAttempt | None,
|
||||
) -> dict[str, Any]:
|
||||
return {
|
||||
"latest_smtp_attempt_number": latest_smtp.attempt_number if latest_smtp else None,
|
||||
"latest_smtp_status": latest_smtp.status if latest_smtp else None,
|
||||
"latest_smtp_status_code": latest_smtp.smtp_status_code if latest_smtp else None,
|
||||
"latest_smtp_started_at": latest_smtp.started_at.isoformat() if latest_smtp and latest_smtp.started_at else None,
|
||||
"latest_smtp_finished_at": latest_smtp.finished_at.isoformat() if latest_smtp and latest_smtp.finished_at else None,
|
||||
"latest_smtp_started_at": _iso_timestamp(latest_smtp.started_at) if latest_smtp else None,
|
||||
"latest_smtp_finished_at": _iso_timestamp(latest_smtp.finished_at) if latest_smtp else None,
|
||||
"latest_imap_attempt_number": latest_imap.attempt_number if latest_imap else None,
|
||||
"latest_imap_status": latest_imap.status if latest_imap else None,
|
||||
"latest_imap_folder": latest_imap.folder if latest_imap else None,
|
||||
"latest_imap_created_at": latest_imap.created_at.isoformat() if latest_imap and latest_imap.created_at else None,
|
||||
"latest_imap_updated_at": latest_imap.updated_at.isoformat() if latest_imap and latest_imap.updated_at else None,
|
||||
})
|
||||
return row
|
||||
"latest_imap_created_at": _iso_timestamp(latest_imap.created_at) if latest_imap else None,
|
||||
"latest_imap_updated_at": _iso_timestamp(latest_imap.updated_at) if latest_imap else None,
|
||||
}
|
||||
|
||||
|
||||
def generate_campaign_report(
|
||||
|
||||
Reference in New Issue
Block a user