fix(go): scan nullable type/payload in receive#285
Draft
NikolayS wants to merge 1 commit into
Draft
Conversation
pgque.message.type and .payload are nullable text, and PgQ legally stores NULL ev_type/ev_data (direct pgque.insert_event calls, trigger-based producers). Receive and ReceiveCoop scanned these columns straight into Go string, so one NULL event errored the whole batch; the batch was never acked and next_batch redelivered it forever -- a poison-message livelock. Scan through nullable temporaries in a shared scanMessage helper and map NULL to "". Keeps the Message API (handler dispatch by Type, json.Unmarshal of Payload) unchanged; a NULL type dispatches as "" and routes through the unknown-handler policy. Server-side nack re-queries canonical event data by msg_id, so the mapping cannot corrupt retry/DLQ rows. Addresses finding B4 of #283. https://claude.ai/code/session_01KAaEGkQZmey1D1xCsVGmqv
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Bug
pgque.message.typeand.payloadare nullable text (sql/pgque-api/receive.sql), and PgQ legally stores NULLev_type/ev_data(directpgque.insert_eventcalls, trigger-based producers). The Go client declaredMessage.TypeandMessage.Payloadas non-nullablestringand scanned the columns directly into them in bothReceiveandReceiveCoop.Scanning a NULL into Go
stringerrors (cannot scan NULL into *string), which fails the WHOLE batch:Receivereturns an error, the batch is never acked, andnext_batchreturns the same batch on every poll — a poison-message livelock from a single NULL event.Fix
Both scan loops now go through a shared
scanMessagehelper that scanstype/payloadinto nullable*stringtemporaries and maps NULL to"".Approach rationale (over switching the fields to
*stringlikeExtra1..4):string: consumer handler dispatch is keyed bymsg.Type(map lookup, string concat in nack reasons), and the documented payload pattern isjson.Unmarshal([]byte(msg.Payload), ...). Pointer fields would break every caller for a rare edge case."", which has no registered handler, so theConsumerroutes it through the existing unknown-handler policy path (Nack by default, or skip withAckUnknown) — no crash, noconsumer.gochanges needed.pgque.nackre-queries the canonical event row bymsg_idfrom the active batch, so the client-sideNULL -> ""mapping cannot corrupt retry/DLQ data.The mapping is documented on the
Messagestruct and onscanMessage.Verification
TDD: the two new integration tests (
clients/go/null_event_test.go) were written first and confirmed red on unfixed code, failing exactly on the bug:The tests install an event with NULL type/data via
select pgque.insert_event(queue, null, null), tick, then assertReceive/ReceiveCoopsucceed, return the message withType == ""andPayload == "", and the batch is ackable.After the fix (scratch DB
pgque_gonull, fresh install ofsql/pgque.sqlon local PostgreSQL 16):Addresses finding B4 of #283
https://claude.ai/code/session_01KAaEGkQZmey1D1xCsVGmqv
Generated by Claude Code