Skip to content

Commit 4fd9e83

Browse files
authored
Merge pull request #1 from netnutmike/Dev
Dev to prod for 1.0.3
2 parents 6869aed + 1e63063 commit 4fd9e83

35 files changed

Lines changed: 3348 additions & 258 deletions

LOCKUP_QUICK_REFERENCE.md

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
# Service Lockup - Quick Reference Card
2+
3+
## 🚨 When Services Lock Up
4+
5+
### Step 1: Capture Diagnostics (DO THIS FIRST!)
6+
```bash
7+
./scripts/debug-lockup.sh
8+
```
9+
**DO NOT RESTART SERVICES UNTIL AFTER RUNNING THIS!**
10+
11+
### Step 2: Review the Report
12+
```bash
13+
# Find the latest report
14+
ls -lt debug-logs/ | head -5
15+
16+
# View it
17+
cat debug-logs/lockup-YYYYMMDD-HHMMSS.log
18+
```
19+
20+
### Step 3: Restart Services
21+
```bash
22+
# Development
23+
docker-compose restart
24+
25+
# Production
26+
docker-compose -f docker-compose.prod.yml restart
27+
```
28+
29+
---
30+
31+
## 📊 Continuous Monitoring
32+
33+
### Start Health Monitor
34+
```bash
35+
# Run in background (checks every 60 seconds)
36+
./scripts/monitor-health.sh &
37+
38+
# Or with custom interval
39+
./scripts/monitor-health.sh 30 &
40+
```
41+
42+
### View Monitor Logs
43+
```bash
44+
tail -f logs/health-monitor.log
45+
```
46+
47+
### Stop Monitor
48+
```bash
49+
pkill -f monitor-health.sh
50+
```
51+
52+
---
53+
54+
## 🔍 What to Look For in Debug Reports
55+
56+
- **OOM Events**: Out of memory kills
57+
- **High CPU/Memory**: Near 100% usage
58+
- **DB Connections**: Count near max_connections
59+
- **Long Queries**: Queries running for minutes
60+
- **DB Locks**: Ungranted locks blocking operations
61+
- **MQTT Issues**: Port not listening or process dead
62+
- **Network Failures**: Services can't reach each other
63+
- **Error Patterns**: Repeated errors in logs
64+
65+
---
66+
67+
## 🛠️ Quick Fixes
68+
69+
### Memory Issues
70+
```bash
71+
# Check memory usage
72+
docker stats --no-stream
73+
74+
# Clean up Docker
75+
docker system prune -a
76+
```
77+
78+
### Disk Space Issues
79+
```bash
80+
# Check disk space
81+
df -h
82+
83+
# Clean up old logs
84+
find ./logs -name "*.log" -mtime +7 -delete
85+
find ./debug-logs -name "*.log" -mtime +7 -delete
86+
```
87+
88+
### Database Issues
89+
```bash
90+
# Check connections
91+
docker-compose exec -T postgres psql -U meshtastic -d meshtastic_mapper -c "SELECT count(*) FROM pg_stat_activity;"
92+
93+
# Check long queries
94+
docker-compose exec -T postgres psql -U meshtastic -d meshtastic_mapper -c "SELECT pid, now() - query_start as duration, query FROM pg_stat_activity WHERE state = 'active' ORDER BY duration DESC LIMIT 5;"
95+
```
96+
97+
### MQTT Issues
98+
```bash
99+
# Check MQTT status
100+
docker-compose exec mosquitto sh -c "ps aux | grep mosquitto"
101+
102+
# Check MQTT port
103+
docker-compose exec mosquitto sh -c "netstat -tlnp | grep 1883"
104+
```
105+
106+
---
107+
108+
## 📚 Full Documentation
109+
110+
- **Complete Guide**: `docs/DEBUGGING_SERVICE_LOCKUPS.md`
111+
- **Implementation Summary**: `docs/fixes/SERVICE_LOCKUP_DEBUGGING.md`
112+
- **Debug Script**: `scripts/debug-lockup.sh`
113+
- **Monitor Script**: `scripts/monitor-health.sh`
114+
115+
---
116+
117+
## 💡 Prevention Tips
118+
119+
1. ✅ Resource limits now configured in docker-compose.yml
120+
2. ✅ MQTT connection limits configured (max: 1000)
121+
3. ✅ Health monitoring scripts available
122+
4. 🔄 Run health monitor continuously in production
123+
5. 🔄 Set up log rotation
124+
6. 🔄 Review debug reports after each lockup
125+
126+
---
127+
128+
## 📞 Reporting Issues
129+
130+
When reporting lockup issues, include:
131+
1. Debug report from `debug-logs/`
132+
2. Health monitor logs (if running)
133+
3. What was happening when lockup occurred
134+
4. Frequency of lockups
135+
5. Any recent changes

TODO.md

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,32 @@
55
| Priority | Description | Status |
66
|----------|-------------|--------|
77
| High | Decryption and Protobuf decoding are not working properly | ✅ Complete - Fixed encryption algorithm, nonce handling, and key management |
8+
| High | Services locking up and requiring restart | 🔧 In Progress - Debug tools created, resource limits added |
89
| Medium | Network topology graph link is not working, it takes the user to the map | Complete |
9-
| Medium | Map center on user is not working | Non-Issue |
10+
| Medium | Map center on user is not working | ✅ Complete - Fixed MUI Tooltip warning |
1011
| Medium | Map startup on user location not working | Non-Issue |
1112
| Low | Hardware types are not complete and may even be wrong | Complete |
13+
| Medium | Device Telemetry do not appear to be saving | 🔧 Fixed - Added enhanced logging, needs testing |
14+
| Medium | Device Neighbors not being recorded | 🔧 Fixed - Added NeighborInfo parsing and storage, needs testing |
15+
| Low | Hardware names are not being proeprly shown on small node details window | Fixed |
16+
| Low | Hardware names are not being properly shown on large node details window in overview and details tabs | Fixed |
17+
| Low | In Node detail window on the Lora Config tab, There is a blue box at the bottom that is off the window | Not Started |
18+
| Medium | Cluster count icons are not working correctly when you click on them or zoom in on the map | Not Started |
1219

1320
## Incomplete Features
1421

1522
| Priority | Description | Status |
1623
|----------|-------------|--------|
1724
| High | Docker deployment not complete | Not Started |
18-
| Medium | MQTT monitor statistics has issues like rounding, no numbers in messages by type and top nodes are showing the decimal value | Complete |
25+
| Medium | MQTT monitor statistics has issues like rounding, no numbers in messages by type and top nodes are showing the decimal value | Complete - Fixed decryption failures count and messages per minute calculation |
1926

2027
## Changes
2128

2229
| Priority | Description | Status |
2330
|----------|-------------|--------|
2431
| Low | About window needs restructured to represent the application and move about meshtastic down below the about for the application, it should link to the github repo for the application. The system information at the bottom is not properly represented. | ✅ Complete |
32+
| Medium | Make node icons and cluster icons larger | Not Started |
33+
| Low | Add option to map options to show node name on map | Not Started |
2534

2635
## New Features
2736

backend/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "meshtastic-node-mapper-backend",
3-
"version": "1.0.2",
3+
"version": "1.0.3",
44
"description": "Backend API for Meshtastic Node Mapper",
55
"main": "dist/index.js",
66
"scripts": {

example decryption.py renamed to backend/src/__tests__/fixtures/example-decryption.py

File renamed without changes.

backend/src/middleware/rateLimiting.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -122,21 +122,21 @@ export const rateLimiters = {
122122
// Read operations - more lenient
123123
read: createApiKeyAwareRateLimiter({
124124
windowMs: 60 * 60 * 1000, // 1 hour
125-
max: process.env.NODE_ENV === 'development' ? 10000 : 5000, // Higher limit in dev
125+
max: process.env.NODE_ENV === 'development' ? 50000 : 5000, // Much higher limit in dev
126126
message: 'Too many read requests. Please try again later.'
127127
}),
128128

129129
// Write operations - more restrictive
130130
write: createApiKeyAwareRateLimiter({
131131
windowMs: 60 * 60 * 1000, // 1 hour
132-
max: 500,
132+
max: process.env.NODE_ENV === 'development' ? 5000 : 500, // Higher limit in dev
133133
message: 'Too many write requests. Please try again later.'
134134
}),
135135

136136
// Real-time data endpoints - very lenient for legitimate use
137137
realtime: createApiKeyAwareRateLimiter({
138138
windowMs: 60 * 1000, // 1 minute
139-
max: process.env.NODE_ENV === 'development' ? 500 : 200, // Higher limit in dev
139+
max: process.env.NODE_ENV === 'development' ? 5000 : 200, // Much higher limit in dev
140140
message: 'Too many real-time requests. Please slow down.'
141141
}),
142142

backend/src/services/mqtt-manager.service.ts

Lines changed: 107 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -254,14 +254,45 @@ export class MQTTManagerService extends EventEmitter {
254254

255255
// Store telemetry data
256256
if (data.telemetry) {
257-
await tx.telemetryReading.create({
258-
data: {
259-
...data.telemetry,
260-
nodeId: node.id,
261-
data: data.telemetry.data as any // Cast to satisfy Prisma JSON type
257+
try {
258+
await tx.telemetryReading.create({
259+
data: {
260+
...data.telemetry,
261+
nodeId: node.id,
262+
data: data.telemetry.data as any // Cast to satisfy Prisma JSON type
263+
}
264+
});
265+
logger.info(`Stored ${data.telemetry.type} telemetry for node: ${data.nodeId}`);
266+
267+
// Also update the node's telemetry fields for quick access
268+
if (data.telemetry.type === 'DEVICE_METRICS' && data.telemetry.data) {
269+
const metrics = data.telemetry.data as any;
270+
const updateData: any = {};
271+
272+
if (metrics.batteryLevel !== undefined) {
273+
updateData.batteryLevel = metrics.batteryLevel;
274+
}
275+
if (metrics.voltage !== undefined) {
276+
updateData.voltage = metrics.voltage;
277+
}
278+
if (metrics.channelUtilization !== undefined) {
279+
updateData.channelUtilization = metrics.channelUtilization;
280+
}
281+
if (metrics.airUtilTx !== undefined) {
282+
updateData.airUtilTx = metrics.airUtilTx;
283+
}
284+
285+
if (Object.keys(updateData).length > 0) {
286+
await tx.node.update({
287+
where: { id: node.id },
288+
data: updateData
289+
});
290+
logger.debug(`Updated node ${data.nodeId} with latest device metrics`);
291+
}
262292
}
263-
});
264-
logger.debug(`Stored telemetry for node: ${data.nodeId}`);
293+
} catch (error) {
294+
logger.error(`Failed to store telemetry for node ${data.nodeId}:`, error);
295+
}
265296
}
266297

267298
// Store message data
@@ -301,6 +332,75 @@ export class MQTTManagerService extends EventEmitter {
301332
});
302333
logger.debug(`Stored message from node: ${data.nodeId}`);
303334
}
335+
336+
// Store neighbor data
337+
if (data.neighbors && data.neighbors.length > 0) {
338+
logger.debug(`Processing ${data.neighbors.length} neighbors for node: ${data.nodeId}`);
339+
340+
for (const neighborData of data.neighbors) {
341+
// Find or create the neighbor node
342+
let neighborNode = await tx.node.findUnique({
343+
where: { nodeId: neighborData.neighborId }
344+
});
345+
346+
// If neighbor node doesn't exist, create a minimal entry
347+
if (!neighborNode) {
348+
try {
349+
neighborNode = await tx.node.create({
350+
data: {
351+
nodeId: neighborData.neighborId,
352+
hexId: neighborData.neighborId.replace('!', ''),
353+
networkId,
354+
isOnline: true,
355+
mqttConnected: false
356+
}
357+
});
358+
logger.debug(`Created neighbor node: ${neighborData.neighborId}`);
359+
} catch (error: any) {
360+
// Handle race condition
361+
if (error.code === 'P2002') {
362+
neighborNode = await tx.node.findUnique({
363+
where: { nodeId: neighborData.neighborId }
364+
});
365+
} else {
366+
logger.error(`Failed to create neighbor node ${neighborData.neighborId}:`, error);
367+
continue;
368+
}
369+
}
370+
}
371+
372+
if (!neighborNode) {
373+
logger.warn(`Could not create or find neighbor node: ${neighborData.neighborId}`);
374+
continue;
375+
}
376+
377+
// Upsert the neighbor relationship
378+
try {
379+
await tx.nodeNeighbor.upsert({
380+
where: {
381+
nodeId_neighborId: {
382+
nodeId: node.id,
383+
neighborId: neighborNode.id
384+
}
385+
},
386+
update: {
387+
snr: neighborData.snr,
388+
lastHeard: neighborData.lastHeard,
389+
updatedAt: new Date()
390+
},
391+
create: {
392+
nodeId: node.id,
393+
neighborId: neighborNode.id,
394+
snr: neighborData.snr,
395+
lastHeard: neighborData.lastHeard
396+
}
397+
});
398+
logger.debug(`Stored neighbor relationship: ${data.nodeId} -> ${neighborData.neighborId}`);
399+
} catch (error) {
400+
logger.error(`Failed to store neighbor relationship for ${data.nodeId} -> ${neighborData.neighborId}:`, error);
401+
}
402+
}
403+
}
304404
}, {
305405
maxWait: 5000, // Maximum time to wait for a transaction slot
306406
timeout: 30000, // Maximum time for the transaction to complete

0 commit comments

Comments
 (0)