Guard tag link against missing vCon (CON-617)#195
Open
howethomas wants to merge 1 commit into
Open
Conversation
VconRedis.get_vcon returns None on a Redis/storage miss (documented "halt the chain" contract). The tag link called .add_tag on the result without a None check, so any evicted/expired vCon crashed with 'NoneType' object has no attribute 'add_tag' and was dropped to the DLQ. ~376k such errors on BDS 2026-06-07..09 during a chain-latency incident. Halt the chain on None, matching the existing tag_router link. Adds a regression test mocking get_vcon -> None. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
Guards the conserver tag link against missing vCons by honoring the documented VconRedis.get_vcon(...) -> Optional[Vcon] contract (None halts the chain) and adds a regression test to prevent crashes/ DLQ drops on Redis/storage misses.
Changes:
- Add a
Noneguard inlinks.tag.run(...)to returnNone(halt chain) whenget_vconmisses. - Log when the vCon is missing instead of crashing with
NoneTypeattribute access. - Add a regression test asserting the chain halts and
store_vconis not called whenget_vconreturnsNone.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| conserver/links/tag/init.py | Adds a None guard + log, returning None to halt the chain when a vCon can’t be loaded. |
| conserver/links/tag/test_tag.py | Adds a regression test covering the missing-vCon path. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+19
to
+24
| if vCon is None: | ||
| # get_vcon returns None when the vCon is missing from Redis and every | ||
| # storage backend (evicted/expired under chain latency). None is the | ||
| # documented "halt the chain" contract, so stop rather than crash. | ||
| logger.warning(f"tag: vCon {vcon_uuid} not found, halting chain") | ||
| return None |
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.
Problem
The conserver
taglink crashes with'NoneType' object has no attribute 'add_tag'and drops the vCon to the DLQ wheneverVconRedis.get_vcon(vcon_uuid)returnsNone.get_vcon(common/lib/vcon_redis.py) is typedOptional[vcon.Vcon]and its docstring statesNoneis the documented "halt the chain" contract for conserver links (Redis miss with no storage hit). Thetaglink had noNoneguard and called.add_tagstraight away.On BDS this fired ~376k times between 2026-06-07 and 2026-06-09, peaking ~126k per 10 min during a chain-latency incident (p95 processing ~2.5h) — delayed vCons had expired/evicted from Redis by the time the lagging tag link reached them.
Fix
Halt the chain on
None, matching the existingtag_routerlink (conserver/links/tag_router/__init__.py:40already doesif not vcon: return None).Test
Adds
test_run_halts_chain_when_vcon_missingmockingget_vcon→None, assertingrun(...)returnsNoneandstore_vconis never called. The existing tests never mocked aNonereturn, which is why this stayed green.All 4 tag tests pass locally.
Linear: CON-617