Skip to content

Commit d2bfdaa

Browse files
committed
fix(completion): extend cache TTL to 5 min + respect --profile on regions
Two fixes for shell tab-completion latency and correctness. TTL was 30 seconds, which is too short for active terminals — users typing in bursts often crossed the boundary and paid for a fresh Keystone auth + list on every tab. Bump CACHE_TTL to 300 seconds; completion data (server names, flavor IDs, region lists) changes slowly and the old short TTL made the tab key feel sluggish. _complete_regions in main.py ignored --profile / ORCA_PROFILE, so a user with several profiles pointing at different clouds saw one cloud's regions cached for the other. It now walks the context chain (same pattern as _build_client in core/completions.py), caches per-profile and loads the matching config. Updated the cache-expiry test to key its "past timestamp" off the actual CACHE_TTL constant.
1 parent a8a5b71 commit d2bfdaa

3 files changed

Lines changed: 27 additions & 9 deletions

File tree

orca_cli/core/cache.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
1-
"""Resource completion cache — 30-second TTL JSON cache for shell completion."""
1+
"""Resource completion cache — per-profile JSON cache for shell completion.
2+
3+
The TTL is long on purpose (5 minutes): completion data — server names,
4+
flavor IDs, region lists — changes slowly, and every cache miss pays for
5+
a Keystone auth round-trip plus the resource GET. Short TTLs made the
6+
tab key feel sluggish on live terminals where users type in bursts.
7+
"""
28

39
from __future__ import annotations
410

511
import json
612
import time
713
from pathlib import Path
814

9-
CACHE_TTL = 30 # seconds
15+
CACHE_TTL = 300 # seconds — long enough to cover typical tab-complete sessions
1016
_CACHE_DIR = Path.home() / ".orca" / "cache"
1117

1218

orca_cli/main.py

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -118,20 +118,31 @@ def _complete_regions(ctx: click.Context, param: click.Parameter, incomplete: st
118118
"""Shell completion for the global --region flag.
119119
120120
Invoked by the shell, not exercised in pytest. Best-effort: all exceptions
121-
swallow to empty — never crash the user's tab key. Results are cached for
122-
30 seconds to avoid a Keystone round-trip on every Tab press.
121+
swallow to empty — never crash the user's tab key. Results are cached
122+
per-profile so users with several profiles don't see a mixed region
123+
list.
123124
"""
124125
try:
125126
from orca_cli.core import cache
126127

127-
cached = cache.load(None, "regions")
128+
# Resolve the active profile so the cache file stays distinct across
129+
# profiles (``~/.orca/cache/<profile>_regions.json``).
130+
profile = None
131+
c: click.Context | None = ctx
132+
while c:
133+
if "profile" in getattr(c, "params", {}) and c.params["profile"]:
134+
profile = c.params["profile"]
135+
break
136+
c = c.parent
137+
138+
cached = cache.load(profile, "regions")
128139
if cached is not None:
129140
return sorted(r["id"] for r in cached if r["id"].startswith(incomplete))
130141

131142
from orca_cli.core.client import OrcaClient
132143
from orca_cli.core.config import config_is_complete, load_config
133144

134-
config = load_config()
145+
config = load_config(profile_name=profile)
135146
if not config_is_complete(config):
136147
return []
137148
client = OrcaClient(config)
@@ -142,7 +153,7 @@ def _complete_regions(ctx: click.Context, param: click.Parameter, incomplete: st
142153
if region:
143154
regions.add(region)
144155
client.close()
145-
cache.save(None, "regions", [{"id": r} for r in sorted(regions)])
156+
cache.save(profile, "regions", [{"id": r} for r in sorted(regions)])
146157
return sorted(r for r in regions if r.startswith(incomplete))
147158
except Exception:
148159
return []

tests/test_wait_and_dryrun.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,10 @@ def test_save_and_hit(self, tmp_path, monkeypatch):
3535
def test_expired_returns_none(self, tmp_path, monkeypatch):
3636
monkeypatch.setattr("orca_cli.core.cache._CACHE_DIR", tmp_path)
3737
items = [{"id": "abc", "name": "my-vm"}]
38-
# Write with a timestamp 60 seconds in the past
38+
# Write with a timestamp well past the TTL
3939
p = tmp_path / "default_servers.json"
40-
p.write_text(json.dumps({"ts": time.time() - 60, "items": items}))
40+
p.write_text(json.dumps({"ts": time.time() - (cache.CACHE_TTL + 60),
41+
"items": items}))
4142
assert cache.load(None, "servers") is None
4243

4344
def test_invalidate_removes_file(self, tmp_path, monkeypatch):

0 commit comments

Comments
 (0)