NotifyPendingApprovalAsync is a thin fire-and-forget wrapper suitable for goroutine launches from HTTP handlers. It swallows the error after logging so callers don't need to.
(msg *identity.Message, agent *identity.AgentIdentity)
| 139 | // for goroutine launches from HTTP handlers. It swallows the error |
| 140 | // after logging so callers don't need to. |
| 141 | func (n *Notifier) NotifyPendingApprovalAsync(msg *identity.Message, agent *identity.AgentIdentity) { |
| 142 | if n == nil { |
| 143 | // Operator-side misconfiguration: notifier wasn't wired (most |
| 144 | // likely because OutboundSMTP.FromDomain or HTTP.PublicURL is |
| 145 | // unset; the wiring in cmd/e2a/main.go gates on both). The API |
| 146 | // still returns 202 pending_review to the caller, but the |
| 147 | // reviewer never gets an email — silent and confusing without |
| 148 | // a log line. |
| 149 | msgID := "" |
| 150 | if msg != nil { |
| 151 | msgID = msg.ID |
| 152 | } |
| 153 | log.Printf("[hitl-notify] suppressed (notifier not configured): msg=%s", msgID) |
| 154 | return |
| 155 | } |
| 156 | go func() { |
| 157 | // Detach from the request context so shutting down mid-notification |
| 158 | // doesn't drop the email. Cap the total send time generously. |
| 159 | ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute) |
| 160 | defer cancel() |
| 161 | if err := n.NotifyPendingApproval(ctx, msg, agent); err != nil { |
| 162 | log.Printf("[hitl-notify] send failed: msg=%s err=%v", msg.ID, err) |
| 163 | } |
| 164 | }() |
| 165 | } |
| 166 | |
| 167 | func (n *Notifier) magicURL(path, token string) string { |
| 168 | if n.publicURL == "" { |