Repository navigation
fix(relay): describe an error as text a database can store - #22
Open
johnnyhuirilef wants to merge 1 commit into
Open
johnnyhuirilef wants to merge 1 commit into
johnnyhuirilef wants to merge 1 commit into
Conversation
PostgreSQL refuses U+0000 in text and jsonb, and a lone UTF-16 surrogate
in jsonb. describeError() let both through. A lone surrogate comes from the
message of JSON.parse('馃榾 not json') in V8, or from the cut at 2000 units
when it splits an emoji.
The store then threw, fail() returned 'lost', attempts stayed at 0 and the
message ran again with no limit. It never reached the dead-letter table.
describeError() now replaces U+0000 with U+FFFD, so a reader sees that
something was there. It calls toWellFormed() after the cut, because the cut
can create the lone surrogate. Both steps apply to every kind of input.
The lib option of both tsconfig files adds ES2024.String for toWellFormed().
Node.js 20.19 and later has it.
Closes nestjs#21
Open
2 of 4 tasks
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.
PR Checklist
PR Type
What is the current behavior?
Issue Number: #21
Closes #21
Hi! 馃憢 With the PostgreSQL store, a message never reaches the dead-letter table when its handler throws an error whose text holds U+0000 or a lone UTF-16 surrogate. The relay runs the handler again each time the lease expires, with no limit.
describeError()keeps the text as it is and cuts it at 2000 code units. The cut can split an emoji, and V8 puts a lone\ud83din the message ofJSON.parse('馃榾 not json'). PostgreSQL refuses both injsonb(and U+0000 intext). The store call throws,fail()returns'lost', andattemptsstays at 0.I ran the repro on 0.1.1. The handler ran 7 times with a limit of 3, and the message was never dead-lettered:
What is the new behavior?
describeError()replaces U+0000 with U+FFFD. A reader can still see that something was there.toWellFormed()after the cut, because the cut can create the lone surrogate. This turns a lone surrogate into U+FFFD.liboption of both tsconfig files addsES2024.String, so TypeScript knowstoWellFormed(). Node.js 20.19 and later has it.The same repro against a local build of this branch:
Does this PR introduce a breaking change?
The text of an error that was storable before stays the same.
Other information
The new specs cover these cases:
tests/unit.spec.ts: U+0000 in an error, in a thrown string and in the errors of an aggregate, also more than one in a text. A cut that splits a pair at index 1999. The lone surrogate in the message of a realJSON.parseerror. A text that needs no change keeps its value and its cut.tests/postgres/store.spec.ts:reschedule()anddeadLetter()accept the description of these three errors. This runs on PGlite. The PostgreSQL target of the same suite is skipped when no server is available, and it was skipped on my machine. In CI, it runs on a PostgreSQL server.I wrote each spec first and saw it fail. I also changed each line of
describeError()and saw a spec fail.I did not change
fail(). It still returns'lost'when the store throws for any other reason. A fallback there, such as a dead letter with a fixed error text, would stop a message from looping on an error that I did not think of. I am happy to open that as a separate PR if you want it. 馃檪The payload has the same problem on
add(). A U+0000 or a lone surrogate in a payload string makesadd()throw inside the caller's transaction on the PostgreSQL store. The in-memory store accepts both. I ran this on PGlite, and issue #21 names the U+0000 case. I can open a separate issue if that helps.