Compare commits

..

2 Commits

Author SHA1 Message Date
a8f9d2ac0d Fix API Mobile Admin
API – Admin User (Mobile)
- src/app/api/mobile/admin/user/route.ts

Docs
- PROMPT-AI.md

### No Issue
2026-02-12 17:42:06 +08:00
d43f3762a3 Fixed Bug Server
## Summary
This branch contains several bug fixes and performance improvements, primarily focusing on:
- Database connection management
- MQTT client stability
- Logging optimization
- API enhancements

## Detailed Changes

### Fixed Issues
1. **Database Connection Management**
   - Removed  from user-validate API route to prevent connection pool exhaustion
   - Added proper connection handling in global Prisma setup
   - Reduced logging verbosity in production environments

2. **MQTT Client Improvements**
   - Enhanced MQTT client initialization with proper error handling
   - Added reconnection logic with configurable intervals
   - Implemented cleanup functions to prevent memory leaks
   - Added separate initialization logic for server and client-side code

3. **Logging Optimization**
   - Removed excessive logging in middleware that was causing high CPU usage
   - Configured appropriate log levels for development and production

4. **Component Stability**
   - Added safety checks in text editor component to prevent MQTT operations on the server side
   - Improved MQTT publishing logic with client availability checks

### New Files
-  - Utility functions for safe database operations

### Modified Files
1.
   - Removed problematic  call

2.
   - Configured different logging levels for dev/prod
   - Removed process listeners that were causing disconnections
   - Exported prisma instance separately

3.
   - Removed excessive logging statements

4.
   - Enhanced initialization with error handling
   - Added reconnection and timeout configurations

5.
   - Added proper cleanup functions
   - Improved connection handling

6.
   - Added MQTT client availability checks
   - Prevented server-side MQTT operations

### Performance Improvements
- Reduced database connection overhead
- Optimized MQTT connection handling
- Eliminated unnecessary logging in production
- Better memory management with proper cleanup functions

### No Issue
2026-02-12 16:29:03 +08:00
10 changed files with 213 additions and 53 deletions

63
CHANGELOG_BRANCH.md Normal file
View File

@@ -0,0 +1,63 @@
# Changelog for Branch: fixed-bug/12-feb-26
## Summary
This branch contains several bug fixes and performance improvements, primarily focusing on:
- Database connection management
- MQTT client stability
- Logging optimization
- API enhancements
## Detailed Changes
### Fixed Issues
1. **Database Connection Management**
- Removed `prisma.$disconnect()` from user-validate API route to prevent connection pool exhaustion
- Added proper connection handling in global Prisma setup
- Reduced logging verbosity in production environments
2. **MQTT Client Improvements**
- Enhanced MQTT client initialization with proper error handling
- Added reconnection logic with configurable intervals
- Implemented cleanup functions to prevent memory leaks
- Added separate initialization logic for server and client-side code
3. **Logging Optimization**
- Removed excessive logging in middleware that was causing high CPU usage
- Configured appropriate log levels for development and production
4. **Component Stability**
- Added safety checks in text editor component to prevent MQTT operations on the server side
- Improved MQTT publishing logic with client availability checks
### New Files
- `src/lib/prismaUtils.ts` - Utility functions for safe database operations
### Modified Files
1. `src/app/api/user-validate/route.ts`
- Removed problematic `prisma.$disconnect()` call
2. `src/lib/prisma.ts`
- Configured different logging levels for dev/prod
- Removed process listeners that were causing disconnections
- Exported prisma instance separately
3. `src/middleware.tsx`
- Removed excessive logging statements
4. `src/util/mqtt_client.ts`
- Enhanced initialization with error handling
- Added reconnection and timeout configurations
5. `src/util/mqtt_loader.tsx`
- Added proper cleanup functions
- Improved connection handling
6. `src/app_modules/_global/component/new/comp_V3_text_editor_stiker.tsx`
- Added MQTT client availability checks
- Prevented server-side MQTT operations
### Performance Improvements
- Reduced database connection overhead
- Optimized MQTT connection handling
- Eliminated unnecessary logging in production
- Better memory management with proper cleanup functions

View File

@@ -1,5 +1,5 @@
File utama: src/app/api/mobile/donation/[id]/donatur/route.ts
File utama: src/app/api/mobile/admin/user/route.ts
Terapkan pagination pada file "File utama" pada method GET
Analisa juga file "File utama", jika belum memiliki page dari seachParams maka terapkan. Juga pastikan take dan skip sudah sesuai dengan pagination. Buat default nya menjadi 10 untuk take data

View File

@@ -1,5 +1,6 @@
import { NextResponse } from "next/server";
import { prisma } from "@/lib";
import { PAGINATION_DEFAULT_TAKE } from "@/lib/constans-value/constansValue";
import { NextResponse } from "next/server";
export { GET };
@@ -7,10 +8,16 @@ async function GET(request: Request) {
const { searchParams } = new URL(request.url);
const search = searchParams.get("search");
const category = searchParams.get("category");
const page = Number(searchParams.get("page"));
const takeData = PAGINATION_DEFAULT_TAKE;
const skipData = page * takeData - takeData;
console.log("SEARCH", search);
console.log("PAGE", page);
let fixData;
try {
if(category === "only-user"){
if (category === "only-user") {
fixData = await prisma.user.findMany({
orderBy: {
updatedAt: "desc",
@@ -22,8 +29,10 @@ async function GET(request: Request) {
mode: "insensitive",
},
},
take: page ? takeData : undefined,
skip: page ? skipData : undefined,
});
} else if(category === "only-admin"){
} else if (category === "only-admin") {
fixData = await prisma.user.findMany({
orderBy: {
updatedAt: "desc",
@@ -35,8 +44,10 @@ async function GET(request: Request) {
mode: "insensitive",
},
},
take: page ? takeData : undefined,
skip: page ? skipData : undefined,
});
} else if (category === "all-role"){
} else if (category === "all-role") {
fixData = await prisma.user.findMany({
orderBy: {
updatedAt: "desc",
@@ -48,13 +59,15 @@ async function GET(request: Request) {
},
{
masterUserRoleId: "2",
}
},
],
username: {
contains: search || "",
mode: "insensitive",
},
},
take: page ? takeData : undefined,
skip: page ? skipData : undefined,
});
}
@@ -65,13 +78,11 @@ async function GET(request: Request) {
data: fixData,
});
} catch (error) {
return NextResponse.json(
{
status: 500,
success: false,
message: "Error get data user access",
reason: (error as Error).message,
},
);
return NextResponse.json({
status: 500,
success: false,
message: "Error get data user access",
reason: (error as Error).message,
});
}
}

View File

@@ -84,7 +84,7 @@ export async function GET(req: Request) {
},
{ status: 500 }
);
} finally {
await prisma.$disconnect();
}
// Removed prisma.$disconnect() from here to prevent connection pool exhaustion
// Prisma connections are handled globally and shouldn't be disconnected on each request
}

View File

@@ -28,6 +28,7 @@ import { useRouter } from "next/navigation";
import { IconMoodSmileFilled } from "@tabler/icons-react";
import { listStiker } from "../../lib/stiker";
import { UIGlobal_Modal } from "../../ui";
import mqtt_client from "@/util/mqtt_client";
const ReactQuill = dynamic(
async () => {
@@ -248,10 +249,12 @@ function ButtonAction({ value, lengthData }: ButtonActionProps) {
ComponentGlobal_NotifikasiBerhasil(create.message);
router.back();
mqtt_client.publish(
"Forum_create_new",
JSON.stringify({ isNewPost: true, count: 1 })
);
if (typeof window !== 'undefined' && mqtt_client) {
mqtt_client.publish(
"Forum_create_new",
JSON.stringify({ isNewPost: true, count: 1 })
);
}
} else {
ComponentGlobal_NotifikasiGagal(create.message);
}

View File

@@ -9,30 +9,21 @@ declare global {
let prisma: PrismaClient;
if (process.env.NODE_ENV === "production") {
prisma = new PrismaClient();
prisma = new PrismaClient({
// Reduce logging in production to improve performance
log: ['error', 'warn'],
});
} else {
if (!global.prisma) {
global.prisma = new PrismaClient();
global.prisma = new PrismaClient({
log: ['error', 'warn', 'info', 'query'], // More verbose logging in development
});
}
prisma = global.prisma;
}
// Tambahkan listener hanya jika belum ditambahkan sebelumnya
if (!global.prismaListenersAdded) {
// Handle uncaught errors
process.on("uncaughtException", async (error) => {
console.error("Uncaught Exception:", error);
await prisma.$disconnect();
process.exit(1);
});
// Handle unhandled promise rejections
process.on("unhandledRejection", async (error) => {
console.error("Unhandled Rejection:", error);
await prisma.$disconnect();
process.exit(1);
});
// Handle graceful shutdown
process.on("SIGINT", async () => {
console.log("Received SIGINT signal. Closing database connections...");
@@ -51,3 +42,4 @@ if (!global.prismaListenersAdded) {
}
export default prisma;
export { prisma };

24
src/lib/prismaUtils.ts Normal file
View File

@@ -0,0 +1,24 @@
import { prisma } from './prisma';
/**
* Utility function to safely execute Prisma operations
* This prevents improper disconnection of the Prisma client
* which was causing high CPU usage and connection pool issues
*/
export async function executeDbOperation<T>(
operation: () => Promise<T>,
errorMessage: string = "Database operation failed"
): Promise<{ success: boolean; data?: T; error?: string }> {
try {
const data = await operation();
return { success: true, data };
} catch (error) {
console.error(errorMessage, error);
return { success: false, error: (error as Error).message };
}
// Note: We intentionally do NOT call prisma.$disconnect() here
// Prisma manages connection pooling automatically and disconnecting
// on each request causes performance issues
}
export { prisma };

View File

@@ -66,9 +66,10 @@ export const middleware = async (req: NextRequest) => {
const { pathname } = req.nextUrl;
const apiBaseUrl = new URL(req.url).origin || process.env.NEXT_PUBLIC_API_URL;
const dbUrl = process.env.DATABASE_URL;
console.log("DATABASE_URL >>", dbUrl);
console.log("URL Access >>", req.url);
// Removed excessive logging that was causing high CPU usage
// const dbUrl = process.env.DATABASE_URL;
// console.log("DATABASE_URL >>", dbUrl);
// console.log("URL Access >>", req.url);
// Handle CORS preflight
const corsResponse = handleCors(req);

View File

@@ -4,7 +4,66 @@ declare global {
var mqtt_client: mqtt.MqttClient;
}
const mqtt_client =
globalThis.mqtt_client || mqtt.connect("wss://io.wibudev.com");
// Initialize MQTT client with proper error handling and reconnection settings
let mqtt_client: mqtt.MqttClient;
if (typeof window === 'undefined') {
// Server-side code
mqtt_client = globalThis.mqtt_client || (() => {
const client = mqtt.connect("wss://io.wibudev.com", {
reconnectPeriod: 5000, // Reconnect every 5 seconds
connectTimeout: 30 * 1000, // 30 second timeout
// Clean session to avoid message queue buildup
clean: true,
// Reduce unnecessary pings
keepalive: 60
});
// Prevent multiple initializations
globalThis.mqtt_client = client;
// Add error handling
client.on('error', (error) => {
console.error('MQTT Connection Error:', error);
});
client.on('reconnect', () => {
console.log('MQTT Reconnecting...');
});
client.on('close', () => {
console.log('MQTT Connection Closed');
});
return client;
})();
} else {
// Client-side code - initialize only once
if (!(globalThis as any).mqtt_client) {
(globalThis as any).mqtt_client = mqtt.connect("wss://io.wibudev.com", {
reconnectPeriod: 5000, // Reconnect every 5 seconds
connectTimeout: 30 * 1000, // 30 second timeout
// Clean session to avoid message queue buildup
clean: true,
// Reduce unnecessary pings
keepalive: 60
});
// Add error handling
(globalThis as any).mqtt_client.on('error', (error: any) => {
console.error('MQTT Connection Error:', error);
});
(globalThis as any).mqtt_client.on('reconnect', () => {
console.log('MQTT Reconnecting...');
});
(globalThis as any).mqtt_client.on('close', () => {
console.log('MQTT Connection Closed');
});
}
mqtt_client = (globalThis as any).mqtt_client;
}
export default mqtt_client;

View File

@@ -3,20 +3,27 @@
import { useEffect } from "react";
import mqtt_client from "./mqtt_client";
export default function MqttLoader() {
export default function MqttLoader() {
useEffect(() => {
mqtt_client.on("connect", () => {
console.log("connected");
});
// Only set up connection handlers once
const handleConnect = () => {
console.log("MQTT connected");
};
const handleError = (error: any) => {
console.error("MQTT Error:", error);
};
// Subscribe to events
mqtt_client.on("connect", handleConnect);
mqtt_client.on("error", handleError);
// Cleanup function to unsubscribe when component unmounts
return () => {
mqtt_client.off("connect", handleConnect);
mqtt_client.off("error", handleError);
};
}, []);
return null;
// <>
// <Stack>
// <Button onClick={onClick}>Tekan</Button>
// <Button onClick={onClick2}>Tekan 2</Button>
// </Stack>
// </>
// );
}