moai-adk 0.4.4__py3-none-any.whl → 0.4.7__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of moai-adk might be problematic. Click here for more details.
- moai_adk/__init__.py +1 -1
- moai_adk/core/project/initializer.py +12 -5
- moai_adk/templates/.claude/agents/alfred/skill-factory.md +829 -0
- moai_adk/templates/.claude/skills/moai-alfred-code-reviewer/SKILL.md +78 -77
- moai_adk/templates/.claude/skills/moai-alfred-code-reviewer/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-alfred-code-reviewer/reference.md +28 -0
- moai_adk/templates/.claude/skills/moai-alfred-debugger-pro/SKILL.md +87 -77
- moai_adk/templates/.claude/skills/moai-alfred-debugger-pro/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-alfred-debugger-pro/reference.md +28 -0
- moai_adk/templates/.claude/skills/moai-alfred-ears-authoring/SKILL.md +76 -66
- moai_adk/templates/.claude/skills/moai-alfred-ears-authoring/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-alfred-ears-authoring/reference.md +28 -0
- moai_adk/templates/.claude/skills/moai-alfred-git-workflow/SKILL.md +86 -59
- moai_adk/templates/.claude/skills/moai-alfred-git-workflow/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-alfred-git-workflow/reference.md +29 -0
- moai_adk/templates/.claude/skills/moai-alfred-language-detection/SKILL.md +87 -73
- moai_adk/templates/.claude/skills/moai-alfred-language-detection/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-alfred-language-detection/reference.md +28 -0
- moai_adk/templates/.claude/skills/moai-alfred-performance-optimizer/SKILL.md +87 -79
- moai_adk/templates/.claude/skills/moai-alfred-performance-optimizer/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-alfred-performance-optimizer/reference.md +28 -0
- moai_adk/templates/.claude/skills/moai-alfred-refactoring-coach/SKILL.md +87 -71
- moai_adk/templates/.claude/skills/moai-alfred-refactoring-coach/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-alfred-refactoring-coach/reference.md +28 -0
- moai_adk/templates/.claude/skills/moai-alfred-spec-metadata-validation/SKILL.md +78 -62
- moai_adk/templates/.claude/skills/moai-alfred-spec-metadata-validation/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-alfred-spec-metadata-validation/reference.md +28 -0
- moai_adk/templates/.claude/skills/moai-alfred-tag-scanning/SKILL.md +78 -55
- moai_adk/templates/.claude/skills/moai-alfred-tag-scanning/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-alfred-tag-scanning/reference.md +28 -0
- moai_adk/templates/.claude/skills/moai-alfred-trust-validation/SKILL.md +78 -64
- moai_adk/templates/.claude/skills/moai-alfred-trust-validation/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-alfred-trust-validation/reference.md +28 -0
- moai_adk/templates/.claude/skills/moai-alfred-tui-survey/SKILL.md +604 -56
- moai_adk/templates/.claude/skills/moai-alfred-tui-survey/examples.md +974 -44
- moai_adk/templates/.claude/skills/moai-alfred-tui-survey/reference.md +801 -0
- moai_adk/templates/.claude/skills/moai-claude-code/SKILL.md +88 -61
- moai_adk/templates/.claude/skills/moai-claude-code/examples.md +16 -500
- moai_adk/templates/.claude/skills/moai-claude-code/reference.md +15 -420
- moai_adk/templates/.claude/skills/moai-domain-backend/SKILL.md +234 -43
- moai_adk/templates/.claude/skills/moai-domain-backend/examples.md +1633 -0
- moai_adk/templates/.claude/skills/moai-domain-backend/reference.md +660 -0
- moai_adk/templates/.claude/skills/moai-domain-cli-tool/SKILL.md +97 -69
- moai_adk/templates/.claude/skills/moai-domain-cli-tool/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-domain-cli-tool/reference.md +30 -0
- moai_adk/templates/.claude/skills/moai-domain-data-science/SKILL.md +97 -72
- moai_adk/templates/.claude/skills/moai-domain-data-science/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-domain-data-science/reference.md +30 -0
- moai_adk/templates/.claude/skills/moai-domain-database/SKILL.md +97 -74
- moai_adk/templates/.claude/skills/moai-domain-database/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-domain-database/reference.md +30 -0
- moai_adk/templates/.claude/skills/moai-domain-devops/SKILL.md +98 -74
- moai_adk/templates/.claude/skills/moai-domain-devops/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-domain-devops/reference.md +31 -0
- moai_adk/templates/.claude/skills/moai-domain-frontend/SKILL.md +98 -73
- moai_adk/templates/.claude/skills/moai-domain-frontend/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-domain-frontend/reference.md +31 -0
- moai_adk/templates/.claude/skills/moai-domain-ml/SKILL.md +97 -73
- moai_adk/templates/.claude/skills/moai-domain-ml/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-domain-ml/reference.md +30 -0
- moai_adk/templates/.claude/skills/moai-domain-mobile-app/SKILL.md +97 -67
- moai_adk/templates/.claude/skills/moai-domain-mobile-app/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-domain-mobile-app/reference.md +30 -0
- moai_adk/templates/.claude/skills/moai-domain-security/SKILL.md +97 -79
- moai_adk/templates/.claude/skills/moai-domain-security/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-domain-security/reference.md +30 -0
- moai_adk/templates/.claude/skills/moai-domain-web-api/SKILL.md +97 -71
- moai_adk/templates/.claude/skills/moai-domain-web-api/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-domain-web-api/reference.md +30 -0
- moai_adk/templates/.claude/skills/moai-essentials-debug/SKILL.md +656 -60
- moai_adk/templates/.claude/skills/moai-essentials-debug/examples.md +1107 -0
- moai_adk/templates/.claude/skills/moai-essentials-debug/reference.md +1533 -0
- moai_adk/templates/.claude/skills/moai-essentials-perf/SKILL.md +87 -78
- moai_adk/templates/.claude/skills/moai-essentials-perf/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-essentials-perf/reference.md +28 -0
- moai_adk/templates/.claude/skills/moai-essentials-refactor/SKILL.md +87 -70
- moai_adk/templates/.claude/skills/moai-essentials-refactor/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-essentials-refactor/reference.md +28 -0
- moai_adk/templates/.claude/skills/moai-essentials-review/SKILL.md +87 -86
- moai_adk/templates/.claude/skills/moai-essentials-review/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-essentials-review/reference.md +28 -0
- moai_adk/templates/.claude/skills/moai-foundation-ears/SKILL.md +77 -62
- moai_adk/templates/.claude/skills/moai-foundation-ears/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-foundation-ears/reference.md +28 -0
- moai_adk/templates/.claude/skills/moai-foundation-git/SKILL.md +88 -56
- moai_adk/templates/.claude/skills/moai-foundation-git/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-foundation-git/reference.md +29 -0
- moai_adk/templates/.claude/skills/moai-foundation-langs/SKILL.md +90 -71
- moai_adk/templates/.claude/skills/moai-foundation-langs/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-foundation-langs/reference.md +28 -0
- moai_adk/templates/.claude/skills/moai-foundation-specs/SKILL.md +78 -58
- moai_adk/templates/.claude/skills/moai-foundation-specs/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-foundation-specs/reference.md +28 -0
- moai_adk/templates/.claude/skills/moai-foundation-tags/SKILL.md +78 -51
- moai_adk/templates/.claude/skills/moai-foundation-tags/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-foundation-tags/reference.md +28 -0
- moai_adk/templates/.claude/skills/moai-foundation-trust/SKILL.md +253 -32
- moai_adk/templates/.claude/skills/moai-foundation-trust/examples.md +0 -0
- moai_adk/templates/.claude/skills/moai-foundation-trust/reference.md +1099 -0
- moai_adk/templates/.claude/skills/moai-lang-c/SKILL.md +98 -74
- moai_adk/templates/.claude/skills/moai-lang-c/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-c/reference.md +31 -0
- moai_adk/templates/.claude/skills/moai-lang-clojure/SKILL.md +97 -74
- moai_adk/templates/.claude/skills/moai-lang-clojure/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-clojure/reference.md +30 -0
- moai_adk/templates/.claude/skills/moai-lang-cpp/SKILL.md +98 -76
- moai_adk/templates/.claude/skills/moai-lang-cpp/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-cpp/reference.md +31 -0
- moai_adk/templates/.claude/skills/moai-lang-csharp/SKILL.md +97 -74
- moai_adk/templates/.claude/skills/moai-lang-csharp/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-csharp/reference.md +30 -0
- moai_adk/templates/.claude/skills/moai-lang-dart/SKILL.md +86 -61
- moai_adk/templates/.claude/skills/moai-lang-dart/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-dart/reference.md +30 -0
- moai_adk/templates/.claude/skills/moai-lang-elixir/SKILL.md +98 -73
- moai_adk/templates/.claude/skills/moai-lang-elixir/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-elixir/reference.md +31 -0
- moai_adk/templates/.claude/skills/moai-lang-go/SKILL.md +98 -74
- moai_adk/templates/.claude/skills/moai-lang-go/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-go/reference.md +31 -0
- moai_adk/templates/.claude/skills/moai-lang-haskell/SKILL.md +98 -74
- moai_adk/templates/.claude/skills/moai-lang-haskell/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-haskell/reference.md +31 -0
- moai_adk/templates/.claude/skills/moai-lang-java/SKILL.md +87 -61
- moai_adk/templates/.claude/skills/moai-lang-java/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-java/reference.md +31 -0
- moai_adk/templates/.claude/skills/moai-lang-javascript/SKILL.md +88 -59
- moai_adk/templates/.claude/skills/moai-lang-javascript/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-javascript/reference.md +32 -0
- moai_adk/templates/.claude/skills/moai-lang-julia/SKILL.md +86 -61
- moai_adk/templates/.claude/skills/moai-lang-julia/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-julia/reference.md +30 -0
- moai_adk/templates/.claude/skills/moai-lang-kotlin/SKILL.md +98 -73
- moai_adk/templates/.claude/skills/moai-lang-kotlin/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-kotlin/reference.md +31 -0
- moai_adk/templates/.claude/skills/moai-lang-lua/SKILL.md +86 -61
- moai_adk/templates/.claude/skills/moai-lang-lua/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-lua/reference.md +30 -0
- moai_adk/templates/.claude/skills/moai-lang-php/SKILL.md +86 -61
- moai_adk/templates/.claude/skills/moai-lang-php/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-php/reference.md +30 -0
- moai_adk/templates/.claude/skills/moai-lang-python/SKILL.md +388 -53
- moai_adk/templates/.claude/skills/moai-lang-python/examples.md +624 -0
- moai_adk/templates/.claude/skills/moai-lang-python/reference.md +316 -0
- moai_adk/templates/.claude/skills/moai-lang-r/SKILL.md +97 -73
- moai_adk/templates/.claude/skills/moai-lang-r/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-r/reference.md +30 -0
- moai_adk/templates/.claude/skills/moai-lang-ruby/SKILL.md +98 -73
- moai_adk/templates/.claude/skills/moai-lang-ruby/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-ruby/reference.md +31 -0
- moai_adk/templates/.claude/skills/moai-lang-rust/SKILL.md +98 -74
- moai_adk/templates/.claude/skills/moai-lang-rust/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-rust/reference.md +31 -0
- moai_adk/templates/.claude/skills/moai-lang-scala/SKILL.md +97 -74
- moai_adk/templates/.claude/skills/moai-lang-scala/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-scala/reference.md +30 -0
- moai_adk/templates/.claude/skills/moai-lang-shell/SKILL.md +97 -74
- moai_adk/templates/.claude/skills/moai-lang-shell/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-shell/reference.md +30 -0
- moai_adk/templates/.claude/skills/moai-lang-sql/SKILL.md +98 -74
- moai_adk/templates/.claude/skills/moai-lang-sql/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-sql/reference.md +31 -0
- moai_adk/templates/.claude/skills/moai-lang-swift/SKILL.md +97 -73
- moai_adk/templates/.claude/skills/moai-lang-swift/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-swift/reference.md +30 -0
- moai_adk/templates/.claude/skills/moai-lang-typescript/SKILL.md +90 -59
- moai_adk/templates/.claude/skills/moai-lang-typescript/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-typescript/reference.md +34 -0
- moai_adk/templates/.claude/skills/moai-skill-factory/CHECKLIST.md +482 -0
- moai_adk/templates/.claude/skills/moai-skill-factory/EXAMPLES.md +52 -0
- moai_adk/templates/.claude/skills/moai-skill-factory/INTERACTIVE-DISCOVERY.md +524 -0
- moai_adk/templates/.claude/skills/moai-skill-factory/METADATA.md +477 -0
- moai_adk/templates/.claude/skills/moai-skill-factory/SKILL-UPDATE-ADVISOR.md +577 -0
- moai_adk/templates/.claude/skills/moai-skill-factory/SKILL.md +560 -0
- moai_adk/templates/.claude/skills/moai-skill-factory/STRUCTURE.md +583 -0
- moai_adk/templates/.claude/skills/moai-skill-factory/WEB-RESEARCH.md +526 -0
- moai_adk/templates/.claude/skills/moai-skill-factory/reference.md +69 -0
- moai_adk/templates/.claude/skills/moai-skill-factory/scripts/generate-structure.sh +328 -0
- moai_adk/templates/.claude/skills/moai-skill-factory/scripts/validate-skill.sh +312 -0
- moai_adk/templates/.claude/skills/moai-skill-factory/templates/SKILL_TEMPLATE.md +245 -0
- moai_adk/templates/.claude/skills/moai-skill-factory/templates/examples-template.md +285 -0
- moai_adk/templates/.claude/skills/moai-skill-factory/templates/reference-template.md +278 -0
- moai_adk/templates/.claude/skills/moai-skill-factory/templates/scripts-template.sh +303 -0
- moai_adk/templates/CLAUDE.md +43 -11
- moai_adk-0.4.7.dist-info/METADATA +1162 -0
- moai_adk-0.4.7.dist-info/RECORD +275 -0
- moai_adk-0.4.4.dist-info/METADATA +0 -369
- moai_adk-0.4.4.dist-info/RECORD +0 -152
- {moai_adk-0.4.4.dist-info → moai_adk-0.4.7.dist-info}/WHEEL +0 -0
- {moai_adk-0.4.4.dist-info → moai_adk-0.4.7.dist-info}/entry_points.txt +0 -0
- {moai_adk-0.4.4.dist-info → moai_adk-0.4.7.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,1107 @@
|
|
|
1
|
+
# MoAI Essentials Debug - Real-World Examples
|
|
2
|
+
|
|
3
|
+
## Table of Contents
|
|
4
|
+
1. [Async/Await Debugging (Python)](#asyncawait-debugging-python)
|
|
5
|
+
2. [Goroutine Leak Investigation (Go)](#goroutine-leak-investigation-go)
|
|
6
|
+
3. [Distributed Tracing with OpenTelemetry (Multi-service)](#distributed-tracing-with-opentelemetry-multi-service)
|
|
7
|
+
4. [Kubernetes Pod Crash Debugging](#kubernetes-pod-crash-debugging)
|
|
8
|
+
5. [Memory Leak Diagnosis (Rust)](#memory-leak-diagnosis-rust)
|
|
9
|
+
6. [Race Condition Detection (Go)](#race-condition-detection-go)
|
|
10
|
+
7. [Null Pointer Debugging (TypeScript)](#null-pointer-debugging-typescript)
|
|
11
|
+
8. [Database Query Performance (SQL)](#database-query-performance-sql)
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Async/Await Debugging (Python)
|
|
16
|
+
|
|
17
|
+
### Problem
|
|
18
|
+
FastAPI application experiencing intermittent timeouts and "Event loop is closed" errors.
|
|
19
|
+
|
|
20
|
+
### Stack Trace
|
|
21
|
+
```python
|
|
22
|
+
Traceback (most recent call last):
|
|
23
|
+
File "app.py", line 87, in process_request
|
|
24
|
+
result = await fetch_data()
|
|
25
|
+
File "app.py", line 42, in fetch_data
|
|
26
|
+
async with session.get(url) as response:
|
|
27
|
+
RuntimeError: Event loop is closed
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Investigation Steps
|
|
31
|
+
|
|
32
|
+
#### 1. Reproduce with Debugger
|
|
33
|
+
```python
|
|
34
|
+
# app.py
|
|
35
|
+
import asyncio
|
|
36
|
+
import debugpy
|
|
37
|
+
|
|
38
|
+
# Enable remote debugging
|
|
39
|
+
debugpy.listen(5678)
|
|
40
|
+
print("Waiting for debugger...")
|
|
41
|
+
debugpy.wait_for_client()
|
|
42
|
+
|
|
43
|
+
async def fetch_data():
|
|
44
|
+
# Set breakpoint here
|
|
45
|
+
breakpoint()
|
|
46
|
+
async with session.get(url) as response:
|
|
47
|
+
return await response.json()
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
#### 2. Run with Async Debugging
|
|
51
|
+
```bash
|
|
52
|
+
# Terminal 1: Start app
|
|
53
|
+
python app.py
|
|
54
|
+
|
|
55
|
+
# Terminal 2: Connect VSCode debugger (Remote Attach config)
|
|
56
|
+
# Step through async code
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
#### 3. VSCode launch.json
|
|
60
|
+
```json
|
|
61
|
+
{
|
|
62
|
+
"version": "0.2.0",
|
|
63
|
+
"configurations": [
|
|
64
|
+
{
|
|
65
|
+
"name": "Python: Async Debug",
|
|
66
|
+
"type": "debugpy",
|
|
67
|
+
"request": "attach",
|
|
68
|
+
"connect": {
|
|
69
|
+
"host": "localhost",
|
|
70
|
+
"port": 5678
|
|
71
|
+
},
|
|
72
|
+
"justMyCode": false,
|
|
73
|
+
"pathMappings": [
|
|
74
|
+
{
|
|
75
|
+
"localRoot": "${workspaceFolder}",
|
|
76
|
+
"remoteRoot": "."
|
|
77
|
+
}
|
|
78
|
+
]
|
|
79
|
+
}
|
|
80
|
+
]
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
#### 4. Inspect Async Context
|
|
85
|
+
```python
|
|
86
|
+
# In debugger console
|
|
87
|
+
import asyncio
|
|
88
|
+
loop = asyncio.get_event_loop()
|
|
89
|
+
print(f"Loop running: {loop.is_running()}")
|
|
90
|
+
print(f"Loop closed: {loop.is_closed()}")
|
|
91
|
+
|
|
92
|
+
# Check pending tasks
|
|
93
|
+
tasks = asyncio.all_tasks(loop)
|
|
94
|
+
print(f"Pending tasks: {len(tasks)}")
|
|
95
|
+
for task in tasks:
|
|
96
|
+
print(task)
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Root Cause
|
|
100
|
+
Multiple event loops created; old loop closed while tasks still pending.
|
|
101
|
+
|
|
102
|
+
### Fix
|
|
103
|
+
```python
|
|
104
|
+
# Before (problematic)
|
|
105
|
+
def main():
|
|
106
|
+
loop = asyncio.new_event_loop()
|
|
107
|
+
asyncio.set_event_loop(loop)
|
|
108
|
+
loop.run_until_complete(fetch_data())
|
|
109
|
+
loop.close() # ❌ Closes loop prematurely
|
|
110
|
+
|
|
111
|
+
# After (correct)
|
|
112
|
+
async def main():
|
|
113
|
+
await fetch_data()
|
|
114
|
+
|
|
115
|
+
if __name__ == "__main__":
|
|
116
|
+
asyncio.run(main()) # ✅ Proper lifecycle management
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Test Case
|
|
120
|
+
```python
|
|
121
|
+
# tests/test_fetch_data.py
|
|
122
|
+
import pytest
|
|
123
|
+
import asyncio
|
|
124
|
+
|
|
125
|
+
@pytest.mark.asyncio
|
|
126
|
+
async def test_fetch_data_no_event_loop_error():
|
|
127
|
+
"""Ensure fetch_data doesn't close event loop prematurely."""
|
|
128
|
+
result = await fetch_data()
|
|
129
|
+
assert result is not None
|
|
130
|
+
|
|
131
|
+
# Verify loop still running
|
|
132
|
+
loop = asyncio.get_event_loop()
|
|
133
|
+
assert not loop.is_closed()
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## Goroutine Leak Investigation (Go)
|
|
139
|
+
|
|
140
|
+
### Problem
|
|
141
|
+
Go service memory usage growing indefinitely over time.
|
|
142
|
+
|
|
143
|
+
### Stack Trace
|
|
144
|
+
```
|
|
145
|
+
goroutine 1543 [chan receive]:
|
|
146
|
+
main.processMessages()
|
|
147
|
+
/app/worker.go:42 +0x120
|
|
148
|
+
created by main.startWorker
|
|
149
|
+
/app/worker.go:25 +0x80
|
|
150
|
+
|
|
151
|
+
goroutine 1544 [chan receive]:
|
|
152
|
+
main.processMessages()
|
|
153
|
+
/app/worker.go:42 +0x120
|
|
154
|
+
created by main.startWorker
|
|
155
|
+
/app/worker.go:25 +0x80
|
|
156
|
+
... (1542 more goroutines)
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Investigation Steps
|
|
160
|
+
|
|
161
|
+
#### 1. Enable Goroutine Profiling
|
|
162
|
+
```go
|
|
163
|
+
// main.go
|
|
164
|
+
import (
|
|
165
|
+
"net/http"
|
|
166
|
+
_ "net/http/pprof"
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
func main() {
|
|
170
|
+
// Enable pprof
|
|
171
|
+
go func() {
|
|
172
|
+
log.Println(http.ListenAndServe("localhost:6060", nil))
|
|
173
|
+
}()
|
|
174
|
+
|
|
175
|
+
// ... rest of application
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
#### 2. Capture Goroutine Dump
|
|
180
|
+
```bash
|
|
181
|
+
# Get goroutine count
|
|
182
|
+
curl http://localhost:6060/debug/pprof/goroutine?debug=1 > goroutines.txt
|
|
183
|
+
|
|
184
|
+
# Analyze goroutines
|
|
185
|
+
go tool pprof http://localhost:6060/debug/pprof/goroutine
|
|
186
|
+
(pprof) top
|
|
187
|
+
(pprof) list processMessages
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
#### 3. Debug with Delve
|
|
191
|
+
```bash
|
|
192
|
+
# Attach to running process
|
|
193
|
+
dlv attach $(pgrep myapp)
|
|
194
|
+
|
|
195
|
+
(dlv) goroutines
|
|
196
|
+
Goroutine 1 - User: /app/main.go:15 main.main (0x10a4b20)
|
|
197
|
+
Goroutine 2 - User: /app/worker.go:42 main.processMessages (0x10a5c30)
|
|
198
|
+
... (1542 more)
|
|
199
|
+
|
|
200
|
+
(dlv) goroutine 2 bt
|
|
201
|
+
0 0x000000000043e3e5 in runtime.gopark
|
|
202
|
+
at /usr/local/go/src/runtime/proc.go:363
|
|
203
|
+
1 0x000000000040b5b6 in runtime.chanrecv
|
|
204
|
+
at /usr/local/go/src/runtime/chan.go:583
|
|
205
|
+
2 0x00000000010a5c30 in main.processMessages
|
|
206
|
+
at /app/worker.go:42
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
#### 4. VSCode launch.json
|
|
210
|
+
```json
|
|
211
|
+
{
|
|
212
|
+
"version": "0.2.0",
|
|
213
|
+
"configurations": [
|
|
214
|
+
{
|
|
215
|
+
"name": "Debug with Goroutine Inspection",
|
|
216
|
+
"type": "go",
|
|
217
|
+
"request": "launch",
|
|
218
|
+
"mode": "debug",
|
|
219
|
+
"program": "${workspaceFolder}",
|
|
220
|
+
"showLog": true,
|
|
221
|
+
"logOutput": "debugger",
|
|
222
|
+
"dlvToolPath": "/usr/local/bin/dlv"
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
"name": "Attach to Process",
|
|
226
|
+
"type": "go",
|
|
227
|
+
"request": "attach",
|
|
228
|
+
"mode": "local",
|
|
229
|
+
"processId": "${command:pickProcess}"
|
|
230
|
+
}
|
|
231
|
+
]
|
|
232
|
+
}
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### Root Cause
|
|
236
|
+
Worker goroutines waiting on channel that never gets closed when context cancelled.
|
|
237
|
+
|
|
238
|
+
```go
|
|
239
|
+
// Before (leaking)
|
|
240
|
+
func startWorker(ctx context.Context) {
|
|
241
|
+
msgChan := make(chan Message)
|
|
242
|
+
go func() {
|
|
243
|
+
for msg := range msgChan { // ❌ Never exits if channel not closed
|
|
244
|
+
processMessage(msg)
|
|
245
|
+
}
|
|
246
|
+
}()
|
|
247
|
+
// ... no channel close on ctx.Done()
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// After (fixed)
|
|
251
|
+
func startWorker(ctx context.Context) {
|
|
252
|
+
msgChan := make(chan Message)
|
|
253
|
+
go func() {
|
|
254
|
+
defer close(msgChan)
|
|
255
|
+
for {
|
|
256
|
+
select {
|
|
257
|
+
case msg := <-msgChan:
|
|
258
|
+
processMessage(msg)
|
|
259
|
+
case <-ctx.Done():
|
|
260
|
+
return // ✅ Proper cleanup
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}()
|
|
264
|
+
}
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
### Test Case
|
|
268
|
+
```go
|
|
269
|
+
// worker_test.go
|
|
270
|
+
func TestNoGoroutineLeak(t *testing.T) {
|
|
271
|
+
initialCount := runtime.NumGoroutine()
|
|
272
|
+
|
|
273
|
+
ctx, cancel := context.WithCancel(context.Background())
|
|
274
|
+
startWorker(ctx)
|
|
275
|
+
|
|
276
|
+
time.Sleep(100 * time.Millisecond)
|
|
277
|
+
cancel()
|
|
278
|
+
time.Sleep(100 * time.Millisecond)
|
|
279
|
+
|
|
280
|
+
finalCount := runtime.NumGoroutine()
|
|
281
|
+
assert.Equal(t, initialCount, finalCount, "Goroutine leak detected")
|
|
282
|
+
}
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
---
|
|
286
|
+
|
|
287
|
+
## Distributed Tracing with OpenTelemetry (Multi-service)
|
|
288
|
+
|
|
289
|
+
### Problem
|
|
290
|
+
Request slow across microservices; need to identify bottleneck.
|
|
291
|
+
|
|
292
|
+
### Architecture
|
|
293
|
+
```
|
|
294
|
+
User → API Gateway → Auth Service → User Service → Database
|
|
295
|
+
→ Product Service → Cache
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### Investigation Steps
|
|
299
|
+
|
|
300
|
+
#### 1. Instrument Services with OpenTelemetry
|
|
301
|
+
|
|
302
|
+
**API Gateway (Python/FastAPI)**
|
|
303
|
+
```python
|
|
304
|
+
# gateway/main.py
|
|
305
|
+
from opentelemetry import trace
|
|
306
|
+
from opentelemetry.sdk.trace import TracerProvider
|
|
307
|
+
from opentelemetry.sdk.trace.export import BatchSpanProcessor
|
|
308
|
+
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
|
|
309
|
+
from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor
|
|
310
|
+
|
|
311
|
+
# Setup tracing
|
|
312
|
+
provider = TracerProvider()
|
|
313
|
+
processor = BatchSpanProcessor(OTLPSpanExporter(endpoint="http://jaeger:4317"))
|
|
314
|
+
provider.add_span_processor(processor)
|
|
315
|
+
trace.set_tracer_provider(provider)
|
|
316
|
+
|
|
317
|
+
app = FastAPI()
|
|
318
|
+
FastAPIInstrumentor.instrument_app(app)
|
|
319
|
+
|
|
320
|
+
@app.get("/users/{user_id}")
|
|
321
|
+
async def get_user(user_id: int):
|
|
322
|
+
tracer = trace.get_tracer(__name__)
|
|
323
|
+
|
|
324
|
+
with tracer.start_as_current_span("gateway.get_user") as span:
|
|
325
|
+
span.set_attribute("user.id", user_id)
|
|
326
|
+
|
|
327
|
+
# Call auth service
|
|
328
|
+
with tracer.start_as_current_span("gateway.verify_auth"):
|
|
329
|
+
auth_result = await verify_auth(user_id)
|
|
330
|
+
|
|
331
|
+
# Call user service
|
|
332
|
+
with tracer.start_as_current_span("gateway.fetch_user_data"):
|
|
333
|
+
user_data = await fetch_user_data(user_id)
|
|
334
|
+
|
|
335
|
+
return user_data
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
**User Service (Go)**
|
|
339
|
+
```go
|
|
340
|
+
// user-service/main.go
|
|
341
|
+
import (
|
|
342
|
+
"go.opentelemetry.io/otel"
|
|
343
|
+
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
|
|
344
|
+
"go.opentelemetry.io/otel/sdk/trace"
|
|
345
|
+
)
|
|
346
|
+
|
|
347
|
+
func initTracing() {
|
|
348
|
+
exporter, _ := otlptracegrpc.New(
|
|
349
|
+
context.Background(),
|
|
350
|
+
otlptracegrpc.WithEndpoint("jaeger:4317"),
|
|
351
|
+
otlptracegrpc.WithInsecure(),
|
|
352
|
+
)
|
|
353
|
+
|
|
354
|
+
tp := trace.NewTracerProvider(
|
|
355
|
+
trace.WithBatcher(exporter),
|
|
356
|
+
)
|
|
357
|
+
otel.SetTracerProvider(tp)
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
func GetUser(w http.ResponseWriter, r *http.Request) {
|
|
361
|
+
ctx := r.Context()
|
|
362
|
+
tracer := otel.Tracer("user-service")
|
|
363
|
+
|
|
364
|
+
ctx, span := tracer.Start(ctx, "user-service.get_user")
|
|
365
|
+
defer span.End()
|
|
366
|
+
|
|
367
|
+
userID := chi.URLParam(r, "userID")
|
|
368
|
+
span.SetAttributes(attribute.String("user.id", userID))
|
|
369
|
+
|
|
370
|
+
// Database query with tracing
|
|
371
|
+
ctx, dbSpan := tracer.Start(ctx, "user-service.db_query")
|
|
372
|
+
user, err := db.GetUser(ctx, userID)
|
|
373
|
+
dbSpan.End()
|
|
374
|
+
|
|
375
|
+
if err != nil {
|
|
376
|
+
span.RecordError(err)
|
|
377
|
+
http.Error(w, "User not found", 404)
|
|
378
|
+
return
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
json.NewEncoder(w).Render(user)
|
|
382
|
+
}
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
#### 2. Deploy Jaeger for Trace Collection
|
|
386
|
+
```yaml
|
|
387
|
+
# docker-compose.yml
|
|
388
|
+
version: '3.8'
|
|
389
|
+
services:
|
|
390
|
+
jaeger:
|
|
391
|
+
image: jaegertracing/all-in-one:1.50
|
|
392
|
+
ports:
|
|
393
|
+
- "16686:16686" # Jaeger UI
|
|
394
|
+
- "4317:4317" # OTLP gRPC
|
|
395
|
+
- "4318:4318" # OTLP HTTP
|
|
396
|
+
environment:
|
|
397
|
+
- COLLECTOR_OTLP_ENABLED=true
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
#### 3. Generate Load and Capture Traces
|
|
401
|
+
```bash
|
|
402
|
+
# Start services
|
|
403
|
+
docker-compose up -d
|
|
404
|
+
|
|
405
|
+
# Generate test traffic
|
|
406
|
+
for i in {1..100}; do
|
|
407
|
+
curl http://localhost:8000/users/123
|
|
408
|
+
sleep 0.1
|
|
409
|
+
done
|
|
410
|
+
|
|
411
|
+
# Open Jaeger UI
|
|
412
|
+
open http://localhost:16686
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
#### 4. Analyze Traces in Jaeger UI
|
|
416
|
+
1. Navigate to Jaeger UI
|
|
417
|
+
2. Select service: `api-gateway`
|
|
418
|
+
3. Find slow traces (> 500ms)
|
|
419
|
+
4. Click trace to see waterfall view
|
|
420
|
+
5. Identify bottleneck span
|
|
421
|
+
|
|
422
|
+
**Example Trace Timeline**
|
|
423
|
+
```
|
|
424
|
+
Total: 1,245ms
|
|
425
|
+
├─ gateway.get_user: 1,245ms
|
|
426
|
+
├─ gateway.verify_auth: 45ms
|
|
427
|
+
│ └─ auth-service.verify_token: 42ms
|
|
428
|
+
│ └─ redis.get: 15ms
|
|
429
|
+
├─ gateway.fetch_user_data: 1,180ms ← BOTTLENECK
|
|
430
|
+
└─ user-service.get_user: 1,175ms
|
|
431
|
+
└─ user-service.db_query: 1,165ms ← ROOT CAUSE
|
|
432
|
+
└─ postgres.query: 1,160ms
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
### Root Cause
|
|
436
|
+
Database query missing index on `users.id`.
|
|
437
|
+
|
|
438
|
+
### Fix
|
|
439
|
+
```sql
|
|
440
|
+
-- Add missing index
|
|
441
|
+
CREATE INDEX idx_users_id ON users(id);
|
|
442
|
+
|
|
443
|
+
-- Verify with EXPLAIN
|
|
444
|
+
EXPLAIN ANALYZE SELECT * FROM users WHERE id = 123;
|
|
445
|
+
-- Before: Seq Scan on users (cost=0.00..1245.00 rows=1 width=100) (actual time=1160.234..1160.235 rows=1 loops=1)
|
|
446
|
+
-- After: Index Scan using idx_users_id on users (cost=0.42..8.44 rows=1 width=100) (actual time=0.023..0.024 rows=1 loops=1)
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
### Test Case
|
|
450
|
+
```python
|
|
451
|
+
# tests/test_performance.py
|
|
452
|
+
import pytest
|
|
453
|
+
from opentelemetry import trace
|
|
454
|
+
|
|
455
|
+
@pytest.mark.asyncio
|
|
456
|
+
async def test_get_user_performance():
|
|
457
|
+
"""Ensure /users/{id} responds within 100ms."""
|
|
458
|
+
tracer = trace.get_tracer(__name__)
|
|
459
|
+
|
|
460
|
+
with tracer.start_as_current_span("test.get_user_performance") as span:
|
|
461
|
+
start = time.time()
|
|
462
|
+
response = await client.get("/users/123")
|
|
463
|
+
duration = time.time() - start
|
|
464
|
+
|
|
465
|
+
span.set_attribute("response.duration_ms", duration * 1000)
|
|
466
|
+
|
|
467
|
+
assert response.status_code == 200
|
|
468
|
+
assert duration < 0.1, f"Request took {duration}s, expected < 0.1s"
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
---
|
|
472
|
+
|
|
473
|
+
## Kubernetes Pod Crash Debugging
|
|
474
|
+
|
|
475
|
+
### Problem
|
|
476
|
+
Pod enters `CrashLoopBackOff` state with OOMKilled status.
|
|
477
|
+
|
|
478
|
+
### Symptoms
|
|
479
|
+
```bash
|
|
480
|
+
kubectl get pods
|
|
481
|
+
NAME READY STATUS RESTARTS AGE
|
|
482
|
+
myapp-7d4f8c9b5-xyz 0/1 CrashLoopBackOff 5 10m
|
|
483
|
+
|
|
484
|
+
kubectl describe pod myapp-7d4f8c9b5-xyz
|
|
485
|
+
...
|
|
486
|
+
Last State: Terminated
|
|
487
|
+
Reason: OOMKilled
|
|
488
|
+
Exit Code: 137
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
### Investigation Steps
|
|
492
|
+
|
|
493
|
+
#### 1. Check Logs (Current and Previous)
|
|
494
|
+
```bash
|
|
495
|
+
# Current logs
|
|
496
|
+
kubectl logs myapp-7d4f8c9b5-xyz
|
|
497
|
+
|
|
498
|
+
# Logs before crash
|
|
499
|
+
kubectl logs myapp-7d4f8c9b5-xyz --previous
|
|
500
|
+
|
|
501
|
+
# Output:
|
|
502
|
+
[INFO] Application starting...
|
|
503
|
+
[INFO] Loading dataset (1M records)...
|
|
504
|
+
[WARNING] Memory usage: 450MB
|
|
505
|
+
[WARNING] Memory usage: 750MB
|
|
506
|
+
[ERROR] Out of memory
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
#### 2. Inspect Resource Limits
|
|
510
|
+
```bash
|
|
511
|
+
kubectl get pod myapp-7d4f8c9b5-xyz -o yaml | grep -A 10 resources
|
|
512
|
+
resources:
|
|
513
|
+
limits:
|
|
514
|
+
memory: 512Mi # ❌ Too low
|
|
515
|
+
requests:
|
|
516
|
+
memory: 256Mi
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
#### 3. Debug with Ephemeral Container
|
|
520
|
+
```bash
|
|
521
|
+
# Add debug container to running pod
|
|
522
|
+
kubectl debug -it myapp-7d4f8c9b5-xyz --image=ubuntu --target=myapp
|
|
523
|
+
|
|
524
|
+
# In debug container
|
|
525
|
+
apt-get update && apt-get install -y htop
|
|
526
|
+
htop
|
|
527
|
+
|
|
528
|
+
# Check memory usage patterns
|
|
529
|
+
cat /proc/meminfo
|
|
530
|
+
free -h
|
|
531
|
+
```
|
|
532
|
+
|
|
533
|
+
#### 4. Profile Memory Usage
|
|
534
|
+
```python
|
|
535
|
+
# Add memory profiling to application
|
|
536
|
+
from memory_profiler import profile
|
|
537
|
+
|
|
538
|
+
@profile
|
|
539
|
+
def load_dataset():
|
|
540
|
+
# This function is consuming too much memory
|
|
541
|
+
data = [process_record(r) for r in fetch_records()] # ❌ Loads all into memory
|
|
542
|
+
return data
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
```bash
|
|
546
|
+
# Run with memory profiler
|
|
547
|
+
python -m memory_profiler app.py
|
|
548
|
+
|
|
549
|
+
# Output:
|
|
550
|
+
Line # Mem usage Increment Line Contents
|
|
551
|
+
================================================
|
|
552
|
+
3 125.2 MiB 0.0 MiB @profile
|
|
553
|
+
4 def load_dataset():
|
|
554
|
+
5 875.4 MiB 750.2 MiB data = [process_record(r) for r in fetch_records()]
|
|
555
|
+
6 875.4 MiB 0.0 MiB return data
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
### Root Cause
|
|
559
|
+
Loading entire dataset into memory at once; exceeds pod memory limit.
|
|
560
|
+
|
|
561
|
+
### Fix
|
|
562
|
+
```python
|
|
563
|
+
# Before (memory-intensive)
|
|
564
|
+
def load_dataset():
|
|
565
|
+
data = [process_record(r) for r in fetch_records()] # ❌ 750MB
|
|
566
|
+
return data
|
|
567
|
+
|
|
568
|
+
# After (streaming)
|
|
569
|
+
def load_dataset():
|
|
570
|
+
for record in fetch_records(): # ✅ Process one at a time
|
|
571
|
+
yield process_record(record)
|
|
572
|
+
```
|
|
573
|
+
|
|
574
|
+
**Update Kubernetes Deployment**
|
|
575
|
+
```yaml
|
|
576
|
+
# deployment.yaml
|
|
577
|
+
apiVersion: apps/v1
|
|
578
|
+
kind: Deployment
|
|
579
|
+
metadata:
|
|
580
|
+
name: myapp
|
|
581
|
+
spec:
|
|
582
|
+
template:
|
|
583
|
+
spec:
|
|
584
|
+
containers:
|
|
585
|
+
- name: myapp
|
|
586
|
+
resources:
|
|
587
|
+
limits:
|
|
588
|
+
memory: 1Gi # ✅ Increased limit
|
|
589
|
+
requests:
|
|
590
|
+
memory: 512Mi
|
|
591
|
+
```
|
|
592
|
+
|
|
593
|
+
### Test Case
|
|
594
|
+
```python
|
|
595
|
+
# tests/test_memory.py
|
|
596
|
+
import tracemalloc
|
|
597
|
+
|
|
598
|
+
def test_load_dataset_memory_efficient():
|
|
599
|
+
"""Ensure load_dataset uses < 100MB memory."""
|
|
600
|
+
tracemalloc.start()
|
|
601
|
+
|
|
602
|
+
list(load_dataset()) # Consume generator
|
|
603
|
+
|
|
604
|
+
current, peak = tracemalloc.get_traced_memory()
|
|
605
|
+
tracemalloc.stop()
|
|
606
|
+
|
|
607
|
+
assert peak / 1024 / 1024 < 100, f"Peak memory {peak/1024/1024}MB exceeds 100MB"
|
|
608
|
+
```
|
|
609
|
+
|
|
610
|
+
---
|
|
611
|
+
|
|
612
|
+
## Memory Leak Diagnosis (Rust)
|
|
613
|
+
|
|
614
|
+
### Problem
|
|
615
|
+
Long-running Rust service memory usage increasing over time.
|
|
616
|
+
|
|
617
|
+
### Stack Trace
|
|
618
|
+
```rust
|
|
619
|
+
thread 'main' panicked at 'allocation error: Cannot allocate memory', src/main.rs:142:23
|
|
620
|
+
```
|
|
621
|
+
|
|
622
|
+
### Investigation Steps
|
|
623
|
+
|
|
624
|
+
#### 1. Enable Memory Profiling with Valgrind
|
|
625
|
+
```bash
|
|
626
|
+
# Build with debug symbols
|
|
627
|
+
cargo build --release
|
|
628
|
+
|
|
629
|
+
# Run with Valgrind
|
|
630
|
+
valgrind --leak-check=full --show-leak-kinds=all ./target/release/myapp
|
|
631
|
+
|
|
632
|
+
# Output:
|
|
633
|
+
HEAP SUMMARY:
|
|
634
|
+
in use at exit: 1,048,576 bytes in 1,024 blocks
|
|
635
|
+
total heap usage: 5,120 allocs, 4,096 frees, 52,428,800 bytes allocated
|
|
636
|
+
|
|
637
|
+
LEAK SUMMARY:
|
|
638
|
+
definitely lost: 1,048,576 bytes in 1,024 blocks
|
|
639
|
+
```
|
|
640
|
+
|
|
641
|
+
#### 2. Use Rust-specific Tools
|
|
642
|
+
```bash
|
|
643
|
+
# Install cargo-flamegraph
|
|
644
|
+
cargo install flamegraph
|
|
645
|
+
|
|
646
|
+
# Generate flamegraph
|
|
647
|
+
cargo flamegraph --bin myapp
|
|
648
|
+
|
|
649
|
+
# Opens flamegraph.svg showing allocation hotspots
|
|
650
|
+
```
|
|
651
|
+
|
|
652
|
+
#### 3. Debug with rust-lldb
|
|
653
|
+
```bash
|
|
654
|
+
cargo build
|
|
655
|
+
rust-lldb target/debug/myapp
|
|
656
|
+
|
|
657
|
+
(lldb) breakpoint set -n main
|
|
658
|
+
(lldb) run
|
|
659
|
+
(lldb) memory read --size 8 --format x --count 10 $rsp
|
|
660
|
+
```
|
|
661
|
+
|
|
662
|
+
#### 4. Inspect with AddressSanitizer
|
|
663
|
+
```bash
|
|
664
|
+
# Rebuild with sanitizer
|
|
665
|
+
RUSTFLAGS="-Z sanitizer=address" cargo build --target x86_64-unknown-linux-gnu
|
|
666
|
+
|
|
667
|
+
# Run
|
|
668
|
+
./target/x86_64-unknown-linux-gnu/debug/myapp
|
|
669
|
+
|
|
670
|
+
# Output shows leak locations
|
|
671
|
+
```
|
|
672
|
+
|
|
673
|
+
### Root Cause
|
|
674
|
+
`Rc<RefCell<T>>` circular reference preventing drop.
|
|
675
|
+
|
|
676
|
+
```rust
|
|
677
|
+
// Before (memory leak)
|
|
678
|
+
use std::rc::Rc;
|
|
679
|
+
use std::cell::RefCell;
|
|
680
|
+
|
|
681
|
+
struct Node {
|
|
682
|
+
data: String,
|
|
683
|
+
next: Option<Rc<RefCell<Node>>>,
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
fn create_cycle() {
|
|
687
|
+
let node1 = Rc::new(RefCell::new(Node {
|
|
688
|
+
data: "Node 1".to_string(),
|
|
689
|
+
next: None,
|
|
690
|
+
}));
|
|
691
|
+
|
|
692
|
+
let node2 = Rc::new(RefCell::new(Node {
|
|
693
|
+
data: "Node 2".to_string(),
|
|
694
|
+
next: Some(Rc::clone(&node1)),
|
|
695
|
+
}));
|
|
696
|
+
|
|
697
|
+
node1.borrow_mut().next = Some(Rc::clone(&node2)); // ❌ Cycle!
|
|
698
|
+
} // node1 and node2 never dropped
|
|
699
|
+
|
|
700
|
+
// After (fixed with Weak)
|
|
701
|
+
use std::rc::{Rc, Weak};
|
|
702
|
+
|
|
703
|
+
struct Node {
|
|
704
|
+
data: String,
|
|
705
|
+
next: Option<Weak<RefCell<Node>>>, // ✅ Use Weak to break cycle
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
fn create_no_cycle() {
|
|
709
|
+
let node1 = Rc::new(RefCell::new(Node {
|
|
710
|
+
data: "Node 1".to_string(),
|
|
711
|
+
next: None,
|
|
712
|
+
}));
|
|
713
|
+
|
|
714
|
+
let node2 = Rc::new(RefCell::new(Node {
|
|
715
|
+
data: "Node 2".to_string(),
|
|
716
|
+
next: Some(Rc::downgrade(&node1)), // ✅ Weak reference
|
|
717
|
+
}));
|
|
718
|
+
|
|
719
|
+
node1.borrow_mut().next = Some(Rc::downgrade(&node2));
|
|
720
|
+
} // Properly cleaned up
|
|
721
|
+
```
|
|
722
|
+
|
|
723
|
+
### Test Case
|
|
724
|
+
```rust
|
|
725
|
+
// tests/memory_test.rs
|
|
726
|
+
#[test]
|
|
727
|
+
fn test_no_memory_leak() {
|
|
728
|
+
let initial_allocs = ALLOCATOR.allocated();
|
|
729
|
+
|
|
730
|
+
{
|
|
731
|
+
create_no_cycle();
|
|
732
|
+
} // Scope ends, should free memory
|
|
733
|
+
|
|
734
|
+
let final_allocs = ALLOCATOR.allocated();
|
|
735
|
+
assert_eq!(initial_allocs, final_allocs, "Memory leak detected");
|
|
736
|
+
}
|
|
737
|
+
```
|
|
738
|
+
|
|
739
|
+
---
|
|
740
|
+
|
|
741
|
+
## Race Condition Detection (Go)
|
|
742
|
+
|
|
743
|
+
### Problem
|
|
744
|
+
Intermittent test failures; data corruption in concurrent writes.
|
|
745
|
+
|
|
746
|
+
### Symptoms
|
|
747
|
+
```
|
|
748
|
+
panic: runtime error: invalid memory address or nil pointer dereference
|
|
749
|
+
[signal SIGSEGV: segmentation violation]
|
|
750
|
+
```
|
|
751
|
+
|
|
752
|
+
### Investigation Steps
|
|
753
|
+
|
|
754
|
+
#### 1. Enable Race Detector
|
|
755
|
+
```bash
|
|
756
|
+
# Run tests with race detector
|
|
757
|
+
go test -race ./...
|
|
758
|
+
|
|
759
|
+
# Output:
|
|
760
|
+
==================
|
|
761
|
+
WARNING: DATA RACE
|
|
762
|
+
Write at 0x00c0001a0180 by goroutine 7:
|
|
763
|
+
main.updateCounter()
|
|
764
|
+
/app/counter.go:23 +0x45
|
|
765
|
+
|
|
766
|
+
Previous read at 0x00c0001a0180 by goroutine 6:
|
|
767
|
+
main.getCounter()
|
|
768
|
+
/app/counter.go:15 +0x38
|
|
769
|
+
|
|
770
|
+
Goroutine 7 (running) created at:
|
|
771
|
+
main.main()
|
|
772
|
+
/app/main.go:42 +0x120
|
|
773
|
+
==================
|
|
774
|
+
```
|
|
775
|
+
|
|
776
|
+
#### 2. Debug with Delve + Race Detector
|
|
777
|
+
```bash
|
|
778
|
+
# Build with race detection
|
|
779
|
+
go build -race -o myapp
|
|
780
|
+
|
|
781
|
+
# Debug
|
|
782
|
+
dlv exec ./myapp
|
|
783
|
+
|
|
784
|
+
(dlv) break counter.go:23
|
|
785
|
+
(dlv) continue
|
|
786
|
+
(dlv) print counter
|
|
787
|
+
(dlv) goroutines
|
|
788
|
+
```
|
|
789
|
+
|
|
790
|
+
### Root Cause
|
|
791
|
+
Unsynchronized access to shared counter.
|
|
792
|
+
|
|
793
|
+
```go
|
|
794
|
+
// Before (race condition)
|
|
795
|
+
var counter int
|
|
796
|
+
|
|
797
|
+
func updateCounter() {
|
|
798
|
+
counter++ // ❌ Not atomic
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
func getCounter() int {
|
|
802
|
+
return counter // ❌ Unsynchronized read
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
// After (fixed with mutex)
|
|
806
|
+
import "sync"
|
|
807
|
+
|
|
808
|
+
var (
|
|
809
|
+
counter int
|
|
810
|
+
mu sync.RWMutex
|
|
811
|
+
)
|
|
812
|
+
|
|
813
|
+
func updateCounter() {
|
|
814
|
+
mu.Lock()
|
|
815
|
+
defer mu.Unlock()
|
|
816
|
+
counter++ // ✅ Protected
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
func getCounter() int {
|
|
820
|
+
mu.RLock()
|
|
821
|
+
defer mu.RUnlock()
|
|
822
|
+
return counter // ✅ Protected
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
// Alternative: Use atomic operations
|
|
826
|
+
import "sync/atomic"
|
|
827
|
+
|
|
828
|
+
var counter int64
|
|
829
|
+
|
|
830
|
+
func updateCounter() {
|
|
831
|
+
atomic.AddInt64(&counter, 1) // ✅ Atomic
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
func getCounter() int64 {
|
|
835
|
+
return atomic.LoadInt64(&counter) // ✅ Atomic
|
|
836
|
+
}
|
|
837
|
+
```
|
|
838
|
+
|
|
839
|
+
### Test Case
|
|
840
|
+
```go
|
|
841
|
+
// counter_test.go
|
|
842
|
+
func TestConcurrentCounterAccess(t *testing.T) {
|
|
843
|
+
counter = 0
|
|
844
|
+
|
|
845
|
+
var wg sync.WaitGroup
|
|
846
|
+
iterations := 1000
|
|
847
|
+
goroutines := 10
|
|
848
|
+
|
|
849
|
+
for i := 0; i < goroutines; i++ {
|
|
850
|
+
wg.Add(1)
|
|
851
|
+
go func() {
|
|
852
|
+
defer wg.Done()
|
|
853
|
+
for j := 0; j < iterations; j++ {
|
|
854
|
+
updateCounter()
|
|
855
|
+
}
|
|
856
|
+
}()
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
wg.Wait()
|
|
860
|
+
expected := iterations * goroutines
|
|
861
|
+
assert.Equal(t, int64(expected), getCounter(), "Counter mismatch indicates race condition")
|
|
862
|
+
}
|
|
863
|
+
```
|
|
864
|
+
|
|
865
|
+
---
|
|
866
|
+
|
|
867
|
+
## Null Pointer Debugging (TypeScript)
|
|
868
|
+
|
|
869
|
+
### Problem
|
|
870
|
+
Production error: `Cannot read properties of undefined (reading 'name')`.
|
|
871
|
+
|
|
872
|
+
### Stack Trace
|
|
873
|
+
```
|
|
874
|
+
TypeError: Cannot read properties of undefined (reading 'name')
|
|
875
|
+
at getUserName (user.service.ts:15:23)
|
|
876
|
+
at processUser (user.controller.ts:42:10)
|
|
877
|
+
at async Router.handle (express.js:234:15)
|
|
878
|
+
```
|
|
879
|
+
|
|
880
|
+
### Investigation Steps
|
|
881
|
+
|
|
882
|
+
#### 1. Add Source Maps for Debugging
|
|
883
|
+
```json
|
|
884
|
+
// tsconfig.json
|
|
885
|
+
{
|
|
886
|
+
"compilerOptions": {
|
|
887
|
+
"sourceMap": true,
|
|
888
|
+
"inlineSourceMap": false,
|
|
889
|
+
"outDir": "./dist",
|
|
890
|
+
"rootDir": "./src"
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
```
|
|
894
|
+
|
|
895
|
+
#### 2. Debug with Node Inspector
|
|
896
|
+
```bash
|
|
897
|
+
# Run with inspector
|
|
898
|
+
node --inspect -r ts-node/register src/app.ts
|
|
899
|
+
|
|
900
|
+
# Or debug tests
|
|
901
|
+
node --inspect-brk node_modules/.bin/jest --runInBand
|
|
902
|
+
```
|
|
903
|
+
|
|
904
|
+
#### 3. VSCode Debugging
|
|
905
|
+
```json
|
|
906
|
+
{
|
|
907
|
+
"version": "0.2.0",
|
|
908
|
+
"configurations": [
|
|
909
|
+
{
|
|
910
|
+
"type": "node",
|
|
911
|
+
"request": "launch",
|
|
912
|
+
"name": "TypeScript: Debug",
|
|
913
|
+
"runtimeArgs": ["-r", "ts-node/register"],
|
|
914
|
+
"args": ["${file}"],
|
|
915
|
+
"cwd": "${workspaceFolder}",
|
|
916
|
+
"sourceMaps": true
|
|
917
|
+
}
|
|
918
|
+
]
|
|
919
|
+
}
|
|
920
|
+
```
|
|
921
|
+
|
|
922
|
+
#### 4. Set Breakpoint and Inspect
|
|
923
|
+
```typescript
|
|
924
|
+
// user.service.ts
|
|
925
|
+
export function getUserName(user: User): string {
|
|
926
|
+
// Set breakpoint here
|
|
927
|
+
debugger;
|
|
928
|
+
return user.name; // user is undefined!
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
// In debugger console:
|
|
932
|
+
// > user
|
|
933
|
+
// undefined
|
|
934
|
+
// > user?.name
|
|
935
|
+
// undefined
|
|
936
|
+
```
|
|
937
|
+
|
|
938
|
+
### Root Cause
|
|
939
|
+
Async data not awaited; function called before user fetched.
|
|
940
|
+
|
|
941
|
+
```typescript
|
|
942
|
+
// Before (bug)
|
|
943
|
+
async function processUser(userId: string) {
|
|
944
|
+
const user = fetchUser(userId); // ❌ Missing await
|
|
945
|
+
const name = getUserName(user); // user is Promise<User>, not User
|
|
946
|
+
console.log(name);
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
// After (fixed)
|
|
950
|
+
async function processUser(userId: string) {
|
|
951
|
+
const user = await fetchUser(userId); // ✅ Await promise
|
|
952
|
+
if (!user) {
|
|
953
|
+
throw new Error(`User ${userId} not found`);
|
|
954
|
+
}
|
|
955
|
+
const name = getUserName(user);
|
|
956
|
+
console.log(name);
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
// Better: Use optional chaining
|
|
960
|
+
function getUserName(user: User | undefined): string {
|
|
961
|
+
return user?.name ?? 'Unknown'; // ✅ Safe access
|
|
962
|
+
}
|
|
963
|
+
```
|
|
964
|
+
|
|
965
|
+
### Test Case
|
|
966
|
+
```typescript
|
|
967
|
+
// user.service.test.ts
|
|
968
|
+
describe('getUserName', () => {
|
|
969
|
+
it('should handle undefined user gracefully', () => {
|
|
970
|
+
const result = getUserName(undefined);
|
|
971
|
+
expect(result).toBe('Unknown');
|
|
972
|
+
});
|
|
973
|
+
|
|
974
|
+
it('should return user name when defined', () => {
|
|
975
|
+
const user = { id: '123', name: 'Alice' };
|
|
976
|
+
const result = getUserName(user);
|
|
977
|
+
expect(result).toBe('Alice');
|
|
978
|
+
});
|
|
979
|
+
});
|
|
980
|
+
```
|
|
981
|
+
|
|
982
|
+
---
|
|
983
|
+
|
|
984
|
+
## Database Query Performance (SQL)
|
|
985
|
+
|
|
986
|
+
### Problem
|
|
987
|
+
Dashboard loads slowly; query taking 5+ seconds.
|
|
988
|
+
|
|
989
|
+
### Investigation Steps
|
|
990
|
+
|
|
991
|
+
#### 1. Enable Query Logging
|
|
992
|
+
```sql
|
|
993
|
+
-- PostgreSQL: Enable slow query log
|
|
994
|
+
ALTER SYSTEM SET log_min_duration_statement = 1000; -- 1 second
|
|
995
|
+
SELECT pg_reload_conf();
|
|
996
|
+
|
|
997
|
+
-- Check logs
|
|
998
|
+
SELECT query, calls, total_time, mean_time
|
|
999
|
+
FROM pg_stat_statements
|
|
1000
|
+
ORDER BY total_time DESC
|
|
1001
|
+
LIMIT 10;
|
|
1002
|
+
```
|
|
1003
|
+
|
|
1004
|
+
#### 2. Analyze Query with EXPLAIN
|
|
1005
|
+
```sql
|
|
1006
|
+
-- Original slow query
|
|
1007
|
+
EXPLAIN ANALYZE
|
|
1008
|
+
SELECT u.name, COUNT(o.id) as order_count
|
|
1009
|
+
FROM users u
|
|
1010
|
+
LEFT JOIN orders o ON u.id = o.user_id
|
|
1011
|
+
WHERE u.created_at > '2024-01-01'
|
|
1012
|
+
GROUP BY u.id, u.name
|
|
1013
|
+
ORDER BY order_count DESC;
|
|
1014
|
+
|
|
1015
|
+
-- Output:
|
|
1016
|
+
Sort (cost=15234.56..15235.56 rows=400 width=16) (actual time=5234.123..5234.234 rows=1000 loops=1)
|
|
1017
|
+
-> HashAggregate (cost=15210.00..15214.00 rows=400 width=16) (actual time=5233.456..5233.789 rows=1000 loops=1)
|
|
1018
|
+
-> Hash Left Join (cost=1234.00..12345.00 rows=286500 width=8) (actual time=123.456..4567.890 rows=500000 loops=1)
|
|
1019
|
+
-> Seq Scan on users u (cost=0.00..1245.00 rows=50000 width=8) (actual time=0.012..234.567 rows=50000 loops=1)
|
|
1020
|
+
Filter: (created_at > '2024-01-01'::date)
|
|
1021
|
+
-> Hash (cost=800.00..800.00 rows=30000 width=8) (actual time=123.444..123.444 rows=30000 loops=1)
|
|
1022
|
+
-> Seq Scan on orders o (cost=0.00..800.00 rows=30000 width=8) (actual time=0.010..89.123 rows=30000 loops=1)
|
|
1023
|
+
Planning Time: 1.234 ms
|
|
1024
|
+
Execution Time: 5234.567 ms ← SLOW!
|
|
1025
|
+
```
|
|
1026
|
+
|
|
1027
|
+
#### 3. Identify Missing Indexes
|
|
1028
|
+
```sql
|
|
1029
|
+
-- Check existing indexes
|
|
1030
|
+
SELECT tablename, indexname, indexdef
|
|
1031
|
+
FROM pg_indexes
|
|
1032
|
+
WHERE tablename IN ('users', 'orders');
|
|
1033
|
+
|
|
1034
|
+
-- Missing:
|
|
1035
|
+
-- 1. Index on users.created_at
|
|
1036
|
+
-- 2. Index on orders.user_id
|
|
1037
|
+
```
|
|
1038
|
+
|
|
1039
|
+
#### 4. Add Indexes and Re-test
|
|
1040
|
+
```sql
|
|
1041
|
+
-- Add indexes
|
|
1042
|
+
CREATE INDEX idx_users_created_at ON users(created_at);
|
|
1043
|
+
CREATE INDEX idx_orders_user_id ON orders(user_id);
|
|
1044
|
+
|
|
1045
|
+
-- Re-run EXPLAIN ANALYZE
|
|
1046
|
+
EXPLAIN ANALYZE
|
|
1047
|
+
SELECT u.name, COUNT(o.id) as order_count
|
|
1048
|
+
FROM users u
|
|
1049
|
+
LEFT JOIN orders o ON u.id = o.user_id
|
|
1050
|
+
WHERE u.created_at > '2024-01-01'
|
|
1051
|
+
GROUP BY u.id, u.name
|
|
1052
|
+
ORDER BY order_count DESC;
|
|
1053
|
+
|
|
1054
|
+
-- Output (improved):
|
|
1055
|
+
Sort (cost=234.56..235.56 rows=400 width=16) (actual time=45.123..45.234 rows=1000 loops=1)
|
|
1056
|
+
-> HashAggregate (cost=210.00..214.00 rows=400 width=16) (actual time=44.456..44.789 rows=1000 loops=1)
|
|
1057
|
+
-> Hash Left Join (cost=123.00..200.00 rows=5000 width=8) (actual time=12.345..40.567 rows=5000 loops=1)
|
|
1058
|
+
-> Index Scan using idx_users_created_at on users u (cost=0.42..100.00 rows=5000 width=8) (actual time=0.023..15.234 rows=5000 loops=1)
|
|
1059
|
+
Index Cond: (created_at > '2024-01-01'::date)
|
|
1060
|
+
-> Hash (cost=80.00..80.00 rows=3000 width=8) (actual time=12.321..12.321 rows=3000 loops=1)
|
|
1061
|
+
-> Index Scan using idx_orders_user_id on orders o (cost=0.42..80.00 rows=3000 width=8) (actual time=0.012..8.123 rows=3000 loops=1)
|
|
1062
|
+
Execution Time: 45.567 ms ← 100x FASTER!
|
|
1063
|
+
```
|
|
1064
|
+
|
|
1065
|
+
### Root Cause
|
|
1066
|
+
Missing indexes on frequently queried columns (`users.created_at`, `orders.user_id`).
|
|
1067
|
+
|
|
1068
|
+
### Test Case
|
|
1069
|
+
```python
|
|
1070
|
+
# tests/test_query_performance.py
|
|
1071
|
+
import pytest
|
|
1072
|
+
import time
|
|
1073
|
+
|
|
1074
|
+
def test_dashboard_query_performance(db):
|
|
1075
|
+
"""Ensure dashboard query completes within 100ms."""
|
|
1076
|
+
query = """
|
|
1077
|
+
SELECT u.name, COUNT(o.id) as order_count
|
|
1078
|
+
FROM users u
|
|
1079
|
+
LEFT JOIN orders o ON u.id = o.user_id
|
|
1080
|
+
WHERE u.created_at > '2024-01-01'
|
|
1081
|
+
GROUP BY u.id, u.name
|
|
1082
|
+
ORDER BY order_count DESC
|
|
1083
|
+
"""
|
|
1084
|
+
|
|
1085
|
+
start = time.time()
|
|
1086
|
+
result = db.execute(query)
|
|
1087
|
+
duration = time.time() - start
|
|
1088
|
+
|
|
1089
|
+
assert duration < 0.1, f"Query took {duration}s, expected < 0.1s"
|
|
1090
|
+
assert len(result) > 0, "Query returned no results"
|
|
1091
|
+
```
|
|
1092
|
+
|
|
1093
|
+
---
|
|
1094
|
+
|
|
1095
|
+
## Summary
|
|
1096
|
+
|
|
1097
|
+
These real-world examples demonstrate:
|
|
1098
|
+
1. **Async debugging** with Python debugpy and asyncio inspection
|
|
1099
|
+
2. **Goroutine leak detection** with Delve and pprof
|
|
1100
|
+
3. **Distributed tracing** with OpenTelemetry across microservices
|
|
1101
|
+
4. **Kubernetes debugging** with ephemeral containers and memory profiling
|
|
1102
|
+
5. **Rust memory leaks** using Valgrind and Weak references
|
|
1103
|
+
6. **Go race conditions** with built-in race detector
|
|
1104
|
+
7. **TypeScript null pointers** with optional chaining and type guards
|
|
1105
|
+
8. **SQL performance** with EXPLAIN ANALYZE and index optimization
|
|
1106
|
+
|
|
1107
|
+
Each example follows the **Reproduce → Isolate → Investigate → Fix → Verify** workflow and includes regression tests to prevent recurrence.
|