-
Notifications
You must be signed in to change notification settings - Fork 263
Raise publish_async ack errors on the returned future #994
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -193,6 +193,23 @@ async def test_publish_async(self): | |
|
|
||
| await nc.close() | ||
|
|
||
| @async_test | ||
| async def test_publish_async_error_ack_is_raised(self): | ||
| # Regression for #985: a server error ack must be raised on the | ||
| # returned future rather than being swallowed (logged and left | ||
| # pending forever). | ||
| nc = NATS() | ||
| await nc.connect() | ||
| js = nc.jetstream() | ||
| await js.add_stream(name="AERR", subjects=["aerr"]) | ||
|
|
||
| # Expected-stream mismatch forces the server to return an error ack. | ||
| future = await js.publish_async("aerr", b"data", stream="WRONGSTREAM") | ||
| with pytest.raises(nats.js.errors.APIError): | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Two small tightenings, both hedged:
await asyncio.wait_for(js.publish_async_completed(), timeout=2)
self.assertEqual(js.publish_async_pending(), 0)(Wrapped in Very minor: the file does |
||
| await asyncio.wait_for(future, timeout=2) | ||
|
|
||
| await nc.close() | ||
|
|
||
| @async_test | ||
| async def test_publish_msg_ttl(self): | ||
| """Test per-message TTL feature (requires NATS Server 2.11+)""" | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this
tryblock still leaves the non-error branch exposed to the very bug this PR fixes. The handler at the bottom catches onlyasyncio.CancelledError/asyncio.InvalidStateError, but two statements inside it can raise something else:json.loads(msg.data)→json.JSONDecodeError(aValueError) on a payload that isn't JSONapi.PubAck.from_response(resp)on line 177 →TypeError, sinceBase.from_responseends incls(**params)andPubAck.stream/PubAck.seqhave no defaultsEither one propagates out of the subscription callback into
Subscription._wait_for_msgs, which hands it toerror_cband carries on — so the future is never resolved,handle_donenever runs, the token stays in_publish_async_futures, the semaphore permit is never released, andpublish_async_completed()blocks forever. Same failure mode as #985, just reached down a different branch.Since it's the same defect class, it might be worth having the fallback route to the future as well:
That keeps the current behaviour for the two existing cases and stops anything else from stranding the future.