Skip to content

Commit e0186db

Browse files
committed
docs: add production testing observations
Bug findings from testing production API (http://157.245.108.179:8080): P0 - POST /functions returns 500 (core functionality broken) P1 - Framework exceptions (404, 405) return 500 P2 - Invalid UUID path params return 500 P3 - Invalid JSON/empty body returns 500 Immediate action: Check PGMQ queue setup and fix GlobalExceptionHandler
1 parent 2862409 commit e0186db

1 file changed

Lines changed: 355 additions & 0 deletions

File tree

Lines changed: 355 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,355 @@
1+
# Production Testing Observations
2+
3+
**Date**: December 27, 2025
4+
**Production URL**: http://157.245.108.179:8080
5+
**Tester**: Claude (following Getting Started guide)
6+
7+
---
8+
9+
## Executive Summary
10+
11+
**Production is NOT functional for the core use case.**
12+
13+
The primary workflow (register → compile → execute) is completely blocked because `POST /functions` returns 500. Read-only operations work, but all write operations and error handling have issues.
14+
15+
### Priority Bugs
16+
17+
| Priority | Bug | Impact |
18+
|----------|-----|--------|
19+
| **P0** | POST /functions returns 500 | Core functionality broken |
20+
| **P1** | Framework exceptions return 500 | Poor DX, hard to debug |
21+
| **P2** | Invalid UUID returns 500 | Should be 400 |
22+
| **P3** | Invalid JSON/empty body returns 500 | Should be 400 |
23+
24+
### Immediate Actions Required
25+
26+
1. **SSH into production** and check:
27+
- API logs: `podman logs projectnil-api`
28+
- PGMQ queues exist: `SELECT pgmq.list_queues();`
29+
- Migrations ran: `podman logs projectnil-migrations`
30+
31+
2. **Fix GlobalExceptionHandler** to properly handle:
32+
- `NoResourceFoundException` → 404
33+
- `HttpRequestMethodNotSupportedException` → 405
34+
- `MethodArgumentTypeMismatchException` → 400
35+
- `HttpMessageNotReadableException` → 400
36+
37+
---
38+
39+
## Test Summary
40+
41+
| Test | Expected | Actual | Status |
42+
|------|----------|--------|--------|
43+
| Health check | 200 UP | 200 UP | PASS |
44+
| List functions | 200 [] | 200 [] | PASS |
45+
| Get non-existent function (valid UUID) | 404 | 404 | PASS |
46+
| Get non-existent execution (valid UUID) | 404 | 404 | PASS |
47+
| Unsupported language validation | 415 | 415 | PASS |
48+
| **Register function** | **201** | **500** | **FAIL** |
49+
| Get function (invalid UUID) | 400 | 500 | FAIL |
50+
| Non-existent endpoint | 404 | 500 | FAIL |
51+
| Wrong HTTP method | 405 | 500 | FAIL |
52+
| Empty request body | 400 | 500 | FAIL |
53+
| Invalid JSON | 400 | 500 | FAIL |
54+
55+
---
56+
57+
## Bug #1: POST /functions returns 500 Internal Server Error
58+
59+
### Steps to Reproduce
60+
61+
```bash
62+
export API_URL="http://157.245.108.179:8080"
63+
64+
curl -X POST $API_URL/functions \
65+
-H "Content-Type: application/json" \
66+
-d '{
67+
"name": "add",
68+
"description": "Adds two numbers",
69+
"language": "assemblyscript",
70+
"source": "export function handle(input: string): string { return input; }"
71+
}'
72+
```
73+
74+
### Expected Response
75+
76+
```json
77+
{
78+
"id": "...",
79+
"name": "add",
80+
"status": "PENDING",
81+
"createdAt": "..."
82+
}
83+
```
84+
85+
### Actual Response
86+
87+
```json
88+
{
89+
"timestamp": "2025-12-27T07:40:02.610285242",
90+
"message": "Internal server error",
91+
"error": "Internal Server Error",
92+
"status": 500
93+
}
94+
```
95+
96+
### Analysis
97+
98+
1. **Validation works**: Unsupported language returns proper 415 error
99+
2. **Read operations work**: GET /functions, GET /functions/{id} work correctly
100+
3. **Failure point**: Error occurs after validation, likely during:
101+
- Database save (Function entity)
102+
- PGMQ queue publish (CompilationJob)
103+
104+
### Likely Root Causes
105+
106+
1. **PGMQ queue not initialized**: The `compilation_jobs` queue may not exist in production
107+
2. **Database migration incomplete**: PGMQ extension or queues not created
108+
3. **PGMQ connection issue**: API can't connect to queue
109+
110+
### Recommended Investigation
111+
112+
1. SSH into production and check:
113+
```bash
114+
podman exec projectnil-db psql -U projectnil -d projectnil -c "\dx"
115+
# Should show pgmq extension
116+
117+
podman exec projectnil-db psql -U projectnil -d projectnil -c "SELECT pgmq.list_queues();"
118+
# Should show compilation_jobs, compilation_results
119+
```
120+
121+
2. Check API logs:
122+
```bash
123+
podman logs projectnil-api --tail 50
124+
```
125+
126+
3. Check if migrations ran:
127+
```bash
128+
podman logs projectnil-migrations
129+
```
130+
131+
---
132+
133+
## Observations: What Works
134+
135+
### 1. Health Check
136+
```bash
137+
curl http://157.245.108.179:8080/health
138+
# {"status":"UP"}
139+
```
140+
141+
### 2. List Functions (empty)
142+
```bash
143+
curl http://157.245.108.179:8080/functions
144+
# []
145+
```
146+
147+
### 3. 404 for Non-existent Resources
148+
```bash
149+
curl http://157.245.108.179:8080/functions/00000000-0000-0000-0000-000000000000
150+
# {"timestamp":"...","message":"Function not found: ...","error":"Not Found","status":404}
151+
```
152+
153+
### 4. Language Validation
154+
```bash
155+
curl -X POST http://157.245.108.179:8080/functions \
156+
-H "Content-Type: application/json" \
157+
-d '{"name":"x","language":"rust","source":"x"}'
158+
# {"timestamp":"...","message":"Unsupported language: rust. Supported: [assemblyscript]","error":"Unsupported Media Type","status":415}
159+
```
160+
161+
---
162+
163+
## Bug #2: Missing/Invalid Request Body Returns 500 Instead of 400
164+
165+
### Observations
166+
167+
| Request Issue | Expected | Actual |
168+
|---------------|----------|--------|
169+
| Missing Content-Type header | 415 or 400 | 500 |
170+
| Empty request body | 400 | 500 |
171+
| Invalid JSON `{invalid}` | 400 | 500 |
172+
| Missing required fields | 400 | 415 (language validation first) |
173+
174+
### Examples
175+
176+
```bash
177+
# Empty body - should be 400
178+
curl -X POST http://157.245.108.179:8080/functions \
179+
-H "Content-Type: application/json" -d ''
180+
# Returns 500
181+
182+
# Invalid JSON - should be 400
183+
curl -X POST http://157.245.108.179:8080/functions \
184+
-H "Content-Type: application/json" -d '{invalid}'
185+
# Returns 500
186+
```
187+
188+
### Impact
189+
190+
- Poor developer experience - unhelpful error messages
191+
- Security concern - 500 errors may leak stack traces in logs
192+
193+
### Recommendation
194+
195+
Add proper request validation and JSON parsing error handling in `GlobalExceptionHandler`:
196+
- `HttpMessageNotReadableException` → 400
197+
- `MissingServletRequestParameterException` → 400
198+
- `MethodArgumentTypeMismatchException` → 400
199+
200+
---
201+
202+
## Bug #3: Invalid UUID Path Parameter Returns 500
203+
204+
### Steps to Reproduce
205+
206+
```bash
207+
curl -X POST http://157.245.108.179:8080/functions/not-a-uuid/execute \
208+
-H "Content-Type: application/json" \
209+
-d '{"input": {}}'
210+
```
211+
212+
### Expected
213+
214+
```json
215+
{
216+
"status": 400,
217+
"error": "Bad Request",
218+
"message": "Invalid UUID format: not-a-uuid"
219+
}
220+
```
221+
222+
### Actual
223+
224+
```json
225+
{
226+
"timestamp": "...",
227+
"message": "Internal server error",
228+
"error": "Internal Server Error",
229+
"status": 500
230+
}
231+
```
232+
233+
### Affected Endpoints
234+
235+
- `GET /functions/{id}` with invalid UUID
236+
- `PUT /functions/{id}` with invalid UUID
237+
- `DELETE /functions/{id}` with invalid UUID
238+
- `POST /functions/{id}/execute` with invalid UUID
239+
- `GET /functions/{id}/executions` with invalid UUID
240+
- `GET /executions/{id}` with invalid UUID
241+
242+
### Recommendation
243+
244+
Add `MethodArgumentTypeMismatchException` handler to `GlobalExceptionHandler`:
245+
246+
```java
247+
@ExceptionHandler(MethodArgumentTypeMismatchException.class)
248+
public ResponseEntity<ErrorResponse> handleTypeMismatch(MethodArgumentTypeMismatchException ex) {
249+
String message = String.format("Invalid %s: %s", ex.getName(), ex.getValue());
250+
return ResponseEntity.badRequest().body(new ErrorResponse(400, "Bad Request", message));
251+
}
252+
```
253+
254+
---
255+
256+
## Bug #4: 404 and 405 Errors Return 500
257+
258+
### Observations
259+
260+
```bash
261+
# Non-existent endpoint - should be 404
262+
curl http://157.245.108.179:8080/nonexistent
263+
# Returns 500
264+
265+
# Wrong HTTP method - should be 405
266+
curl -X PATCH http://157.245.108.179:8080/functions
267+
# Returns 500
268+
```
269+
270+
### Impact
271+
272+
- All Spring MVC framework exceptions are being caught by generic handler
273+
- Makes debugging very difficult
274+
- Poor API experience
275+
276+
### Root Cause Theory
277+
278+
The `GlobalExceptionHandler` likely has a catch-all `@ExceptionHandler(Exception.class)` that's swallowing specific exceptions like:
279+
- `NoResourceFoundException` (Spring 6.x) → should be 404
280+
- `HttpRequestMethodNotSupportedException` → should be 405
281+
- `MethodArgumentTypeMismatchException` → should be 400
282+
283+
### Recommendation
284+
285+
Add specific exception handlers BEFORE the generic catch-all:
286+
287+
```java
288+
@ExceptionHandler(NoResourceFoundException.class)
289+
public ResponseEntity<ErrorResponse> handleNotFound(NoResourceFoundException ex) {
290+
return ResponseEntity.status(404).body(...);
291+
}
292+
293+
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
294+
public ResponseEntity<ErrorResponse> handleMethodNotAllowed(...) {
295+
return ResponseEntity.status(405).body(...);
296+
}
297+
```
298+
299+
---
300+
301+
## Observation: Input Validation Order
302+
303+
The execute endpoint validates function existence before input format:
304+
305+
```bash
306+
# With invalid input but non-existent function
307+
curl -X POST $API_URL/functions/00000000.../execute -d '{"input": "string"}'
308+
# Returns 404 (function not found), not 400 (invalid input)
309+
```
310+
311+
This is acceptable behavior (fail-fast on existence) but worth noting:
312+
- Input validation happens inside `ExecutionService.execute()` after function lookup
313+
- A truly invalid request with bad input AND non-existent function returns 404
314+
315+
---
316+
317+
## Unable to Test (Blocked by Bug #1)
318+
319+
Since we can't create functions, the following cannot be tested:
320+
321+
- [ ] GET /functions/{id} (with valid function)
322+
- [ ] PUT /functions/{id}
323+
- [ ] DELETE /functions/{id}
324+
- [ ] POST /functions/{id}/execute
325+
- [ ] GET /functions/{id}/executions
326+
- [ ] GET /executions/{id}
327+
- [ ] Compilation flow (PENDING → COMPILING → READY)
328+
- [ ] Execution flow
329+
330+
---
331+
332+
## Documentation Issues Found
333+
334+
### Issue #1: Getting Started guide assumes local setup works
335+
336+
The guide jumps straight to `curl http://localhost:8080/functions` without verifying the full stack is operational. Consider adding a "verify your setup" section.
337+
338+
### Issue #2: No production troubleshooting section
339+
340+
The guide has troubleshooting for local development but not for production issues.
341+
342+
### Issue #3: Error messages don't help diagnose
343+
344+
The 500 error says "Internal server error" with no actionable details. Consider:
345+
- Adding correlation IDs to error responses
346+
- Logging more context in production logs
347+
348+
---
349+
350+
## Next Steps
351+
352+
1. **Immediate**: Investigate and fix Bug #1 (500 on POST /functions)
353+
2. **After fix**: Complete the testing of all endpoints
354+
3. **Documentation**: Add production troubleshooting guide
355+
4. **Observability**: Add correlation IDs and structured logging

0 commit comments

Comments
 (0)