TestWriteOutboxRow_PgNotifyFailureIsSoft pins the C2 fix: when pg_notify fails (realistically: NOTIFY queue overflow at ~8MB), writeOutboxRow MUST log and return nil so the caller's tx commits. Before the fix the pg_notify error was returned, propagating out of PublishTx → out of WithTx → causing t
(t *testing.T)
| 126 | // NOTIFY fired. The NOTIFY is a latency optimization, not a correctness |
| 127 | // primitive. |
| 128 | func TestWriteOutboxRow_PgNotifyFailureIsSoft(t *testing.T) { |
| 129 | notifyErr := errors.New("ERROR: too many notifications in the NOTIFY queue (SQLSTATE 54000)") |
| 130 | fe := &fakeExec{ |
| 131 | errOnContains: "pg_notify", |
| 132 | errSelective: notifyErr, |
| 133 | } |
| 134 | e := Event{ |
| 135 | ID: "evt_notify_fail", |
| 136 | Type: EventEmailReceived, |
| 137 | UserID: "u_42", |
| 138 | } |
| 139 | if err := writeOutboxRow(context.Background(), fe, e); err != nil { |
| 140 | t.Fatalf("writeOutboxRow should swallow pg_notify failure, got: %v", err) |
| 141 | } |
| 142 | // Both Exec calls must have been attempted — the INSERT first, then |
| 143 | // the (failing) pg_notify. The INSERT must NOT have been skipped. |
| 144 | if len(fe.calls) != 2 { |
| 145 | t.Fatalf("expected 2 Exec calls (INSERT + NOTIFY), got %d: %v", len(fe.calls), fe.calls) |
| 146 | } |
| 147 | if !strings.Contains(fe.calls[0], "INSERT INTO webhook_events") { |
| 148 | t.Errorf("first call must be the INSERT: %s", fe.calls[0]) |
| 149 | } |
| 150 | if !strings.Contains(fe.calls[1], "pg_notify") { |
| 151 | t.Errorf("second call must be the pg_notify: %s", fe.calls[1]) |
| 152 | } |
| 153 | } |
| 154 | |
| 155 | // TestWriteOutboxRow_InsertFailureStillPropagates ensures the soft- |
| 156 | // failure treatment for pg_notify doesn't accidentally swallow INSERT |
nothing calls this directly
no test coverage detected