Release govoplan-campaign v0.1.28: stabilize saving, review and delivery recovery
Module Package Release / publish-packages (push) Successful in 12s
Module Package Release / publish-packages (push) Successful in 12s
This commit is contained in:
@@ -30,9 +30,24 @@ been validated, built, reviewed, and locked.
|
||||
for attempts, outcomes, and reconciliation.
|
||||
- Confirm the effective Send now recipient-job limit. The safe default is 25;
|
||||
use Queue for workers for ordinary batches or any run above that limit.
|
||||
System administrators can explicitly configure 0–500 under Administration →
|
||||
SYSTEM → Campaign delivery; an explicit deployment ceiling remains binding,
|
||||
and TENANT policy may only narrow the inherited limit. This setting affects
|
||||
one synchronous request, not campaign size. It is audited and never sends
|
||||
messages; large interactive requests may encounter proxy timeouts.
|
||||
|
||||
## Deliverability Preflight
|
||||
|
||||
The Mail server connection test checks that selected server and credential. It
|
||||
does not authorize the campaign's sender, recipients, or resource selection.
|
||||
SMTP runtime checks require the selected SMTP credential when policy forbids
|
||||
inheritance, independently of IMAP. Sent-folder append checks IMAP credentials
|
||||
independently; full campaign validation still checks both required selections.
|
||||
Preflight errors distinguish Mail profile/credential policy, SMTP configuration,
|
||||
authentication, and connectivity. Do not change TLS or credential policies merely
|
||||
because a campaign preflight failed. A preflight rejection leaves staged jobs
|
||||
uncommitted and starts no message delivery.
|
||||
|
||||
Before the first live send for a sender domain or mail-server profile:
|
||||
|
||||
- Confirm the selected SMTP identity matches the visible From/envelope sender
|
||||
@@ -50,18 +65,25 @@ Before the first live send for a sender domain or mail-server profile:
|
||||
|
||||
## Queue And Send
|
||||
|
||||
1. Validate the version with file checks enabled.
|
||||
1. Link all required managed files, then validate the version with file checks
|
||||
enabled. Locking waits for a fresh attachment preview and asks for explicit
|
||||
**Link and lock** confirmation when matches are not linked. A locked version
|
||||
cannot change attachment links: use an editable version and repeat validation,
|
||||
build and review rather than assuming unlinked files were included.
|
||||
2. Build the version and inspect all blocking review items.
|
||||
3. Queue only after the selected version is the intended immutable execution
|
||||
version. Select **Queue for workers**, then verify the committed and
|
||||
published counts.
|
||||
4. Use **Send now** only if the exact eligible count is non-zero and at or below
|
||||
the effective deployment/tenant limit shown on the page.
|
||||
the effective deployment/system/tenant limit shown on the page.
|
||||
5. In worker mode, verify queue counters move from queued/claimed/sending to a
|
||||
terminal SMTP state.
|
||||
6. If a synchronous request is used, keep Review and send open: it polls the
|
||||
durable counters while the request runs. A rejection occurs before SMTP and
|
||||
directs oversized runs to workers.
|
||||
6. If a synchronous request is used, keep its blocking progress dialog open.
|
||||
Only its small version-scoped persisted counters refresh; the workspace,
|
||||
recipient list, attachment preview and full summary stay unchanged. Read-only
|
||||
refresh failure retains the last counters and does not prove delivery failed.
|
||||
A disconnected request may still be executing; never repeat it blindly.
|
||||
Oversized initial runs are rejected before SMTP and directed to workers.
|
||||
7. Review the SMTP batch line. `ready` means DNS/connectivity/TLS/auth preflight
|
||||
succeeded. Connection and reconnect counts explain reuse. `paused` means a
|
||||
systemic transport failure stopped the remaining jobs before their SMTP
|
||||
@@ -97,9 +119,10 @@ unknown provider attempt merely to repair the other layer's state.
|
||||
unavailable connectivity affect the batch rather than one recipient.
|
||||
- `outcome_unknown`: Do not retry directly. Check SMTP logs, mailbox evidence, or
|
||||
provider control panels, then reconcile as accepted or not sent.
|
||||
- `claimed` or `sending` that does not progress: treat as a worker interruption.
|
||||
Re-run worker handling or reconcile if SMTP may already have accepted the
|
||||
message.
|
||||
- `claimed` or `sending` that does not progress: investigate the owning runtime.
|
||||
Duplicate worker handling leaves active state unchanged. Never infer from
|
||||
elapsed time alone that SMTP did not accept the message. Use the fenced
|
||||
**Recover interrupted claim** action described below when it is available.
|
||||
- IMAP `appending`: A worker owns the durable append claim. Do not start a
|
||||
second append; if the worker cannot finish, reconcile only after checking the
|
||||
mailbox.
|
||||
@@ -117,6 +140,65 @@ unknown provider attempt merely to repair the other layer's state.
|
||||
- Add a note that identifies the evidence used, for example SMTP log line,
|
||||
provider message ID, or operator ticket.
|
||||
|
||||
For pure-Mail SMTP and channel-specific IMAP operations, reconciliation updates
|
||||
the original Campaign attempt, matching Campaign recovery operation and audit
|
||||
record atomically under a fresh lease. A SMTP-only decision cannot resolve an
|
||||
entire compound Mail/Postbox/Print operation; that ledger remains separately
|
||||
unresolved until all of its effects are established. Campaign does
|
||||
not rewrite Mail-owned nested provider-effect operations: those remain Mail's
|
||||
separate evidence and operational responsibility. A failed audit or conflicting
|
||||
claim must leave the prior unknown state intact.
|
||||
|
||||
### Recovery without workers
|
||||
|
||||
The Report offers explicit inline retry and continuation when workers are not
|
||||
configured. Retry uses `campaigns:campaign:retry` plus
|
||||
`campaigns:campaign:send`; continuation uses `campaigns:campaign:queue` plus
|
||||
`campaigns:campaign:send`. Both use the canonical immutable jobs and ordinary
|
||||
attempt ledger, not a separate one-message resend. Current Mail authorization,
|
||||
review/approval, execution integrity, retry limits and rate limits still apply.
|
||||
Each call is bounded by the effective synchronous recipient-job limit and
|
||||
reports remaining eligible work. Continue explicitly until none remains; it
|
||||
never selects accepted, excluded, active, uncertain or known failed jobs.
|
||||
Known failures have their own explicit retry action. These actions do not
|
||||
turn a long HTTP request into a background worker or guarantee exactly-once
|
||||
SMTP when a provider acknowledgement is lost.
|
||||
|
||||
For an abandoned active SMTP or IMAP claim, the report exposes recovery only
|
||||
after the original durable lease expires **and** the runtime registry proves
|
||||
that its owner stopped or was replaced. A stale heartbeat is insufficient.
|
||||
The opaque claim revision and original recovery evidence are rechecked under a
|
||||
fresh lease. Recovery records the effect as **outcome unknown**, never not sent.
|
||||
Then separately inspect external evidence and reconcile with a factual note
|
||||
before any retry. This requires `campaigns:campaign:reconcile`. If the original
|
||||
lease, evidence, or stopped-owner proof is missing, preserve the records and
|
||||
investigate through Ops; do not edit delivery rows or force a lease expiry in
|
||||
a real installation.
|
||||
|
||||
### Progress totals and Sent-folder batching
|
||||
|
||||
For each channel, **processed** includes successful, failed, uncertain and
|
||||
cancelled outcomes. **In progress** is separate from pending, so the currently
|
||||
sending/appending message remains visible. Paused SMTP work is also separate.
|
||||
Excluded/non-requested channel work is outside the denominator. The endpoint
|
||||
requires campaign read and object access and returns no recipient addresses,
|
||||
message bodies, attachments or credentials. It is not the privacy-thresholded
|
||||
aggregate Reports view and does not grant that view recipient access.
|
||||
|
||||
Append-to-Sent targets the selected campaign version, not all historical
|
||||
versions. Each message remains a separately fenced, sequential IMAP APPEND.
|
||||
Mail reuses the authenticated session and resolved folder for at most 100
|
||||
messages or 300 seconds by default, then rotates the connection. Current
|
||||
authorization, frozen transport revisions, credentials and recovery checks
|
||||
still run for every message. A stale idle connection is checked before another
|
||||
APPEND; an uncertain APPEND is never replayed. This removes repeated
|
||||
connect/login/folder-list round trips, not the time needed to upload each EML.
|
||||
It is not an atomic MULTIAPPEND transaction or parallel delivery.
|
||||
|
||||
SMTP and IMAP use the same progress dialog. An acknowledged operation remains
|
||||
successful even if loading its follow-up diagnostics fails: use Reload to
|
||||
refresh display, not to repeat the external effect.
|
||||
|
||||
## Fault Injection Checklist
|
||||
|
||||
Use mock infrastructure first, then repeat against the non-production real test
|
||||
@@ -141,17 +223,21 @@ deliberately excluded.
|
||||
|
||||
The runner also terminates a dedicated OS process executing the registered
|
||||
Campaign send task after complete DATA, then invokes the task in a fresh
|
||||
process. The unfinished durable attempt must become `outcome_unknown` and the
|
||||
endpoint must observe no second connection or DATA transaction. This covers
|
||||
the worker task/process boundary but not a broker or daemon.
|
||||
process. Redelivery must leave the active claim unchanged and the endpoint
|
||||
must observe no second connection or DATA transaction. Only a subsequent
|
||||
explicit, fenced recovery with test-fixture stopped-owner and expired-lease
|
||||
proof may change the unfinished attempt to `outcome_unknown`. This covers the
|
||||
worker task/process boundary but not a broker or daemon.
|
||||
|
||||
Run `dev/mail-testbed/run_celery_redelivery_acceptance.py` for the maintained
|
||||
Redis/Celery delivery and broker redelivery boundary. It starts an isolated
|
||||
Redis Compose service and real Celery workers, kills the first solo worker after complete DATA while the
|
||||
late-ack task is unacknowledged, and requires the same task identity to reach a
|
||||
replacement worker after Redis visibility recovery. Passing evidence also
|
||||
requires durable `outcome_unknown`, an empty broker queue/unacked set, and
|
||||
exactly one SMTP connection and DATA transaction. Raw worker logs and task,
|
||||
requires unchanged active state on duplicate delivery, followed by explicit
|
||||
fenced recovery to `outcome_unknown`, an empty broker queue/unacked set, and
|
||||
exactly one SMTP connection and DATA transaction. Lease expiration is simulated
|
||||
only in the isolated fixture after its owner was stopped. Raw worker logs and task,
|
||||
database, endpoint, and credential identifiers are never retained.
|
||||
|
||||
That second runner proves local runner-supervised process replacement, not the
|
||||
@@ -190,6 +276,11 @@ and retention.
|
||||
|
||||
## Reporting Checks
|
||||
|
||||
- The recipient-aware report shows every frozen To/Cc/Bcc address in authored
|
||||
order, with a primary-address fallback only for old rows without that snapshot.
|
||||
SMTP envelope evidence, not the old primary-only UI, establishes how many
|
||||
recipients were actually offered to the provider. SMTP and IMAP diagnostics
|
||||
use list filters and consistent translated labels.
|
||||
- Partial delivery must show accepted, failed, and unknown counts separately.
|
||||
- Excluded messages must show SMTP and IMAP as `skipped`, with skipped counts
|
||||
and filters separate from unattempted or failed delivery.
|
||||
|
||||
Reference in New Issue
Block a user