Skip to content

fix(conserver): storage fallback for missing vCons + halt observability - #169

Merged
pavanputhra merged 3 commits into
mainfrom
fix/conserver-b7-storage-fallback
May 19, 2026
Merged

pavanputhra merged 3 commits into
mainfrom
fix/conserver-b7-storage-fallback

Conversation

@pavanputhra

Copy link
Copy Markdown
Contributor

Summary

Three small, layered changes addressing Sentry CONSERVER-B7 (AttributeError: 'NoneType' object has no attribute 'dialog' in deepgram_link.run):

  1. Storage fallback in VconRedis — when a vCon is no longer in Redis (TTL expired or evicted), get_vcon / get_vcon_dict now iterate the configured storage backends, return the first hit, and re-cache it back into Redis with VCON_REDIS_EXPIRY. On by default; opt out with VCON_STORAGE_FALLBACK_ENABLED=false. This makes every link that calls VconRedis.get_vcon resilient to the "vCon UUID hits the chain after Redis TTL" pattern without per-link changes. get_vcon is also refactored to delegate to get_vcon_dict for a single lookup path.

  2. deepgram_link None-guard — defense-in-depth for the case where the storage fallback also misses (or is disabled). Halts the chain cleanly per the docstring contract (return None) instead of dereferencing the missing vCon. Mirrors the existing guard pattern in transcribe, tag_router, jq_link, and check_and_tag.

  3. Halt-vs-success metric split — conserver.link.count previously fired with outcome="success" for both "return uuid" (continue) and "return None" (halt), making it impossible to track which links halt chains. Now uses outcome="halt" when the link returned a falsy value. Existing dashboards filtering on outcome="success" remain accurate; new dashboards can pivot on outcome="halt" with link_name.

Fixes CONSERVER-B7.

Test plan

  • pytest tests/core/test_vcon_redis.py — 10 passing (4 pre-existing + 6 new fallback-path tests: Redis hit, Redis miss + storage hit (re-cache + sorted-set add), Redis miss + storage miss, fallback disabled, first-storage-errors-second-succeeds, dict-variant fallback)
  • pytest tests/core/test_vcon_redis_ttl.py — 24 passing (no regression)
  • pytest conserver/links/deepgram_link/tests/ — 11 passing (1 new test_run_halts_chain_when_vcon_not_found)
  • pytest conserver/tests/test_link_metrics.py conserver/tests/test_vcon_concurrency.py — 34 passing (1 new test_link_halt_records_halt_outcome)

All tests run inside the vcon-server-conserver-1 container.

🤖 Generated with Claude Code

When a vCon is no longer in Redis (TTL expired or evicted), VconRedis
now falls back to the configured storage backends, returning the first
hit and re-caching it back into Redis with VCON_REDIS_EXPIRY. The
behavior is on by default and can be disabled with the new
VCON_STORAGE_FALLBACK_ENABLED setting.

Also refactors get_vcon to delegate to get_vcon_dict (single lookup
path), and consolidates the read metric counters into one family:
get_vcon_redis_miss / get_vcon_storage_hit / get_vcon_not_found.

This makes every link that calls VconRedis.get_vcon resilient to the
"vCon UUID hits the chain after Redis TTL" pattern without needing
per-link guards. Refs CONSERVER-B7.
Guard against VconRedis.get_vcon returning None. With the new storage
fallback this only happens when the vCon is truly gone (missed Redis
and every configured storage), or when VCON_STORAGE_FALLBACK_ENABLED
is off. In either case, dereferencing .dialog crashed the worker with
'NoneType' object has no attribute 'dialog'.

Return None to halt the chain, matching the docstring contract and the
pattern already used by transcribe, tag_router, jq_link, and check_and_tag.

Fixes CONSERVER-B7.
The conserver.link.count counter previously fired with outcome="success"
for both "return uuid" (chain continues) and "return None" (chain halts)
— making it impossible to track which links are halting chains. Split
into outcome="success" vs outcome="halt" based on whether the link
returned a truthy value.

Dashboards already filtering outcome="success" remain accurate (halts
are simply excluded). New dashboards can pivot on outcome="halt" with
link_name to see e.g. "deepgram halted N chains today."
@pavanputhra
pavanputhra merged commit 3c2dcd4 into main May 19, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant