Improve performance and error handling in web components#506
Conversation
- WinnersService: fetch winners-count flag first, then pass the limit directly to GetAllDatabaseWinnersAsync so EF Core applies Take() at the SQL layer instead of loading all rows then discarding most of them - WinnersService: add .AsNoTracking() on the read-only DB query to avoid unnecessary change-tracking overhead - prompt_loader: add @lru_cache(maxsize=10) to load_prompt so each .prompt.yml file is read from disk and parsed only once per process lifetime instead of on every chat request Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- CarCard: remove debug console.log in toggleOwnership handler - Home: remove debug console.log on winners load success and ownership update - FeatureFlagsModal: add fetchError state so users see an error message instead of misleading 'No flags available' when the flags API call fails Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- CarCard: remove debug console.log in toggleOwnership handler - Home: remove debug console.log on winners load success and ownership update - FeatureFlagsModal: add fetchError state so users see an error message instead of misleading 'No flags available' when the flags API call fails Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- WinnersService: fetch winners-count flag first, then pass the limit directly to GetAllDatabaseWinnersAsync so EF Core applies Take() at the SQL layer instead of loading all rows then discarding most of them - WinnersService: add .AsNoTracking() on the read-only DB query to avoid unnecessary change-tracking overhead - prompt_loader: add @lru_cache(maxsize=10) to load_prompt so each .prompt.yml file is read from disk and parsed only once per process lifetime instead of on every chat request Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add test_prompt_loader.py: 12 unit tests covering render_messages,
get_model_parameters, and load_prompt across happy-path and edge cases.
Tests use only stdlib + pytest (no test doubles needed for pure functions).
- Add requirements-test.txt: isolates pytest from the production
requirements.txt so the test dependency does not enter the container image.
Run tests locally with:
pip install -r requirements-test.txt
pytest src/Garage.ChatService/
- Fix fetch() helper in main_test.go: the resp.Body.Close() check used
the idiom 'if err != resp.Body.Close()' which compared the ReadAll error
against the Close error. This silently dropped the Close error value when
the read succeeded (err==nil). Replaced with the correct
'if err := resp.Body.Close(); err != nil' pattern.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Two imports were deferred inside function bodies, against PEP 8 and Python style guidelines: - 'import time' was placed inside chat() on every request, causing a (minor) redundant sys.modules lookup on each call; moved to module level. - 'import grpc' was placed inside setup_telemetry() inside a branch that is only reached when TLS is required; grpc is an explicit production dependency (requirements.txt) so there is no reason to defer it. Moving it to module level makes the dependency visible at a glance and avoids the confusing 'import inside a function' pattern. No behaviour change; py_compile check still passes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The setup-python action uses cache: 'pip' but without cache-dependency-path, it searches the whole repo for dependency files. Since requirements.txt lives in src/Garage.ChatService/, specifying the explicit path ensures the cache key is correctly derived from the actual dependency file — consistent with how the Go and Node.js jobs already configure their caches. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…cking-lru-cache-1f6995db1c2d51e7' into askpt/fix-issues
…p-console-logs-error-state-a11f4ed64e7e51b0' into askpt/fix-issues
…p-console-logs-error-state-a11f4ed64e7e51b0-eb818041601a0760' into askpt/fix-issues
…cking-lru-cache-1f6995db1c2d51e7-cec4b5efd1592c5e' into askpt/fix-issues
…nd-fix-go-test-fetch-29d90cdbf5c43db0' into askpt/fix-issues
…t-cleanup-754b353e4bca722a' into askpt/fix-issues
There was a problem hiding this comment.
Pull request overview
This PR improves runtime efficiency and user feedback across the sample app by pushing winner limits down to the database query layer, caching chatbot prompt parsing, cleaning up frontend debug logging, and introducing clearer error handling for feature-flag fetch failures. It also adds initial Python unit tests for prompt loading/rendering and small CI/pipeline hygiene updates.
Changes:
- Optimize winners retrieval by applying
Take()in EF Core SQL queries and usingAsNoTracking(). - Cache
.prompt.ymlprompt loading in the ChatService and move deferred imports to module scope. - Improve web UX by removing debug logs and showing a fetch error state in
FeatureFlagsModal; add Python unit tests forprompt_loader.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/Garage.ApiService/Services/WinnersService.cs | Pushes winner limiting into DB query and limits JSON results earlier. |
| src/Garage.ChatService/prompt_loader.py | Adds lru_cache to avoid repeated disk I/O and YAML parsing for prompts. |
| src/Garage.ChatService/main.py | Moves time/grpc imports to module level for clarity and minor perf. |
| src/Garage.ChatService/test_prompt_loader.py | Adds pytest unit tests for prompt loading/rendering/model params. |
| src/Garage.ChatService/requirements-test.txt | Introduces isolated test dependency requirements for pytest. |
| src/Garage.FeatureFlags/main_test.go | Fixes response body close error handling in test helper. |
| src/Garage.Web/src/components/Home.tsx | Removes debug console.log statements. |
| src/Garage.Web/src/components/CarCard.tsx | Removes debug console.log statement. |
| src/Garage.Web/src/components/FeatureFlagsModal.tsx | Adds an error UI state when feature-flag fetch fails. |
| .github/workflows/ci.yml | Improves pip cache keying by pinning cache dependency path. |
| global.json | Changes .NET SDK roll-forward behavior (now latestMajor). |
Comments suppressed due to low confidence (2)
src/Garage.ChatService/prompt_loader.py:28
load_promptis now cached, but it returns a mutable dict that callers can mutate. Withlru_cache, any accidental mutation will affect all future callers (shared cached object) and can cause hard-to-debug cross-request behavior. Consider returning an immutable structure or a defensive copy (e.g., deep copy) to prevent cache poisoning via mutation.
@lru_cache(maxsize=10)
def load_prompt(prompt_name: str, prompts_dir: str = "prompts") -> dict[str, Any]:
"""Load a .prompt.yml file and return parsed content.
Results are cached in-memory so repeated calls with the same arguments
avoid redundant disk I/O and YAML parsing.
Args:
prompt_name: Name of the prompt (without extension)
prompts_dir: Directory containing prompt files
Returns:
Parsed YAML content as a dictionary
Raises:
FileNotFoundError: If the prompt file doesn't exist
"""
prompt_path = Path(prompts_dir) / f"{prompt_name}.prompt.yml"
with open(prompt_path, 'r', encoding='utf-8') as f:
return yaml.safe_load(f)
.github/workflows/ci.yml:146
- The new
test_prompt_loader.pysuite isn’t exercised in CI right now:build-pythononly installsrequirements.txtand runspy_compile. If these tests are intended to prevent regressions, add a pytest step (installingrequirements-test.txt) and consider includingrequirements-test.txtincache-dependency-pathso cache keys change when test deps change.
cache-dependency-path: src/Garage.ChatService/requirements.txt
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: Check syntax
run: python -m py_compile main.py prompt_loader.py
You can also share your feedback on Copilot code review. Take the survey.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 11 out of 11 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (1)
.github/workflows/ci.yml:146
- This PR adds pytest-based unit tests under src/Garage.ChatService/, but the build-python job still only runs py_compile and never executes the tests. Consider adding a CI step to install the test requirements and run pytest so these tests actually protect against regressions (and, if you do, include requirements-test.txt in the pip cache key inputs).
python-version: '3.14'
allow-prereleases: true
cache: 'pip'
cache-dependency-path: src/Garage.ChatService/requirements.txt
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: Check syntax
run: python -m py_compile main.py prompt_loader.py
You can also share your feedback on Copilot code review. Take the survey.
Enhance database query efficiency by applying
Take()at the SQL layer and caching prompt files to reduce disk I/O. Remove unnecessary debug logs and implement error handling in the FeatureFlagsModal to provide clearer feedback to users when API calls fail. Add unit tests for the prompt loader functionality to ensure reliability.closes #505
closes #504
closes #503
closes #502
closes #499
closes #498
closes #497
closes #496
closes #495