113 lines
5.8 KiB
Markdown
113 lines
5.8 KiB
Markdown
---
|
|
title: Major Domo v2 Release — 2026.3.20
|
|
description: "Performance release: parallelized API calls, caching improvements, CI overhaul to tag-triggered releases, async hotfix, and chart path fix."
|
|
type: reference
|
|
domain: major-domo
|
|
tags: [discord, major-domo, deployment, release-notes, docker, ci]
|
|
---
|
|
|
|
# Major Domo v2 Release — 2026.3.20
|
|
|
|
**Date:** 2026-03-20
|
|
**Tags:** `2026.3.10`, `2026.3.11` (bugfix)
|
|
**Image:** `manticorum67/major-domo-discordapp:production`
|
|
**Server:** akamai (`/root/container-data/major-domo`)
|
|
**Deploy method:** `.scripts/release.sh` → CI → `.scripts/deploy.sh`
|
|
|
|
## Release Summary
|
|
|
|
Performance-focused release with 12 merged PRs covering parallelized API calls, caching improvements, CI workflow overhaul, and a production hotfix. Also retired the `next-release` staging branch in favor of direct-to-main merges with tag-triggered releases.
|
|
|
|
## Hotfix During Release
|
|
|
|
**PR #117** — ScorecardTracker async mismatch. PR #106 added `await` to all `scorecard_tracker` method calls across `scorebug.py`, `live_scorebug_tracker.py`, and `cleanup_service.py`, but the tracker methods themselves were still synchronous. This caused `TypeError: object NoneType can't be used in 'await' expression` on `/scorebug` and `TypeError: object list can't be used in 'await' expression` in the background scorebug update loop. Fixed by making all 6 public `ScorecardTracker` methods async and adding 5 missing `await`s in `cleanup_service.py`.
|
|
|
|
**Root cause:** PR #106 was created by an issue-worker agent that modified callers without modifying the tracker class. The async tracker conversion existed only in uncommitted working tree changes that were never included in any PR.
|
|
|
|
**Lesson:** Issue-worker agent PRs that add `await` to calls must verify the called methods are actually async — not just that the callers compile.
|
|
|
|
## Infrastructure Changes
|
|
|
|
### CI: Tag-triggered releases (PRs #110, #113)
|
|
|
|
Replaced branch-push CI with tag-push CI. Merging to `main` no longer triggers a Docker build.
|
|
|
|
- **Before:** Push to `main` or `next-release` → auto-build → auto-tag CalVer
|
|
- **After:** Push CalVer tag (`git tag 2026.3.11 && git push --tags`) → build → Docker image tagged `:version` + `:production`
|
|
|
|
Also removed the `pull_request` trigger that was building Docker images on every PR branch push.
|
|
|
|
### Release and deploy scripts (PRs #114, #115)
|
|
|
|
- `.scripts/release.sh` — auto-generates next CalVer tag, shows changelog, confirms, pushes tag
|
|
- `.scripts/deploy.sh` — updated to use SSH alias (`ssh akamai`) and `:production` image tag
|
|
|
|
### Docker volume split (PR #86)
|
|
|
|
Split the single `./storage:/app/data` volume into:
|
|
- `./storage/major-domo-service-creds.json:/app/data/major-domo-service-creds.json:ro` (credentials)
|
|
- `./storage:/app/storage:rw` (state files)
|
|
|
|
Production compose on akamai was updated manually before deploy. All 5 tracker default paths changed from `data/` to `storage/`.
|
|
|
|
### Retired `next-release` branch
|
|
|
|
All references to `next-release` removed from CLAUDE.md and CI workflow. New workflow: branch from `main` → PR to `main` → tag to release.
|
|
|
|
## Performance Changes
|
|
|
|
### Parallelized API calls
|
|
|
|
| PR | What | Impact |
|
|
|----|------|--------|
|
|
| #88 | `schedule_service`: `get_team_schedule`, `get_recent_games`, `get_upcoming_games` use `asyncio.gather()` | Up to 18 sequential HTTP requests → concurrent |
|
|
| #90 | Team lookups in `/publish-scorecard`, `/scorebug`, `/injury`, trade validation | 2 sequential calls → concurrent per location |
|
|
| #102 | `asyncio.gather()` across multiple command files | Broad latency reduction |
|
|
|
|
### Caching
|
|
|
|
| PR | What | Impact |
|
|
|----|------|--------|
|
|
| #99 | Cache user team lookup in `player_autocomplete` with 60s TTL, reduce Discord limit to 25 | Faster autocomplete on repeat use |
|
|
| #98 | Replace Redis `KEYS` with `SCAN` for cache invalidation | Non-blocking invalidation |
|
|
|
|
### Micro-optimizations
|
|
|
|
| PR | What | Impact |
|
|
|----|------|--------|
|
|
| #93 | Use `channel.purge()` instead of per-message `message.delete()` loops | 1 API call vs up to 100 per channel clear |
|
|
| #96 | Replace `json.dumps(value)` probe with `isinstance()` in JSON logger | Eliminates full serialization on every log call |
|
|
| #97 | Cache `inspect.signature()` at decoration time in all 3 decorators | Introspection cost paid once, not per-call |
|
|
|
|
## Cleanup
|
|
|
|
| PR | What |
|
|
|----|------|
|
|
| #104 | Remove dead `@self.tree.interaction_check` decorator block and duplicate `self.maintenance_mode` assignment in `bot.py` |
|
|
| #103 | Remove unused `weeks_ahead` parameter from `get_upcoming_games` |
|
|
|
|
## Test Coverage
|
|
|
|
- 16 new tests for `schedule_service` (`test_services_schedule.py` — first coverage for this service)
|
|
- Tests use existing `GameFactory`/`TeamFactory` from `tests/factories.py`
|
|
- 2 existing scorebug tests updated for async tracker methods
|
|
- Full suite: 967+ tests passing
|
|
|
|
## Bugfix: 2026.3.11
|
|
|
|
**PR #119** — `chart_service.py` CHARTS_FILE path still pointed to `data/charts.json` after PR #86 moved state files to `storage/`. The `/charts` autocomplete returned no results because the file was at `/app/storage/charts.json` but the code read from `/app/data/charts.json`. One-line path fix.
|
|
|
|
**Root cause:** PR #86 updated the 5 tracker classes but missed `ChartService`, which uses a class-level `Path` constant instead of the `__init__` pattern used by the trackers.
|
|
|
|
**Lesson:** When moving file paths across volumes, grep for the old path across the entire codebase — not just the files being modified.
|
|
|
|
## Deployment Notes
|
|
|
|
- Production compose updated on akamai before deploy (volume split for PR #86)
|
|
- Image tag changed from `:latest` to `:production`
|
|
- Deployed three times total:
|
|
1. `2026.3.10` — initial release (broken `/scorebug` and scorebug tracker)
|
|
2. `2026.3.10` — re-tagged after hotfix #117 (async mismatch)
|
|
3. `2026.3.11` — chart path fix (#119)
|
|
- Final deploy confirmed healthy — all background tasks started, gateway connected
|