Log export lifecycle (start/ok/fail/lock) with stack and timing
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
import { NextResponse } from "next/server";
|
import { NextResponse } from "next/server";
|
||||||
import sql from "mssql";
|
import sql from "mssql";
|
||||||
import ExcelJS from "exceljs";
|
import ExcelJS from "exceljs";
|
||||||
|
import { exportLogger, formatError } from "../../../server/logger";
|
||||||
|
|
||||||
const dbConfig = {
|
const dbConfig = {
|
||||||
server: process.env.DB_SERVER!,
|
server: process.env.DB_SERVER!,
|
||||||
@@ -55,7 +56,7 @@ const EXPORT_LOCK_TIMEOUT_MS = 90_000; // safety: reclaim a stuck lock after 90s
|
|||||||
|
|
||||||
function acquireExportLock(): boolean {
|
function acquireExportLock(): boolean {
|
||||||
if (exportLocked && Date.now() - exportLockedAt > EXPORT_LOCK_TIMEOUT_MS) {
|
if (exportLocked && Date.now() - exportLockedAt > EXPORT_LOCK_TIMEOUT_MS) {
|
||||||
console.warn("Export lock reclaimed after timeout");
|
exportLogger.warn("export lock reclaimed after timeout");
|
||||||
exportLocked = false;
|
exportLocked = false;
|
||||||
}
|
}
|
||||||
if (exportLocked) return false;
|
if (exportLocked) return false;
|
||||||
@@ -70,11 +71,14 @@ function releaseExportLock() {
|
|||||||
|
|
||||||
export async function GET() {
|
export async function GET() {
|
||||||
if (!acquireExportLock()) {
|
if (!acquireExportLock()) {
|
||||||
|
exportLogger.warn("export skipped: another export in progress (429)");
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
{ error: "正在导出,请稍候" },
|
{ error: "正在导出,请稍候" },
|
||||||
{ status: 429, headers: { "Retry-After": "3" } }
|
{ status: 429, headers: { "Retry-After": "3" } }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
const t0 = Date.now();
|
||||||
|
exportLogger.info("export started");
|
||||||
let pool: sql.ConnectionPool | undefined;
|
let pool: sql.ConnectionPool | undefined;
|
||||||
try {
|
try {
|
||||||
pool = await sql.connect(dbConfig);
|
pool = await sql.connect(dbConfig);
|
||||||
@@ -84,6 +88,7 @@ export async function GET() {
|
|||||||
|
|
||||||
const recordset = result.recordset;
|
const recordset = result.recordset;
|
||||||
if (!recordset || recordset.length === 0) {
|
if (!recordset || recordset.length === 0) {
|
||||||
|
exportLogger.warn("export empty: no data");
|
||||||
return NextResponse.json({ error: "没有数据可导出" }, { status: 404 });
|
return NextResponse.json({ error: "没有数据可导出" }, { status: 404 });
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,6 +156,12 @@ export async function GET() {
|
|||||||
|
|
||||||
// Stream to buffer
|
// Stream to buffer
|
||||||
const buffer = await workbook.xlsx.writeBuffer();
|
const buffer = await workbook.xlsx.writeBuffer();
|
||||||
|
const bytes =
|
||||||
|
typeof buffer === "object" && buffer && "byteLength" in buffer
|
||||||
|
? (buffer as { byteLength: number }).byteLength
|
||||||
|
: 0;
|
||||||
|
const dur = Date.now() - t0;
|
||||||
|
exportLogger.info(`export ok · rows=${recordset.length} · bytes=${bytes} · dur=${dur}ms`);
|
||||||
|
|
||||||
return new NextResponse(buffer, {
|
return new NextResponse(buffer, {
|
||||||
status: 200,
|
status: 200,
|
||||||
@@ -162,8 +173,9 @@ export async function GET() {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
const dur = Date.now() - t0;
|
||||||
const message = err instanceof Error ? err.message : "Unknown error";
|
const message = err instanceof Error ? err.message : "Unknown error";
|
||||||
console.error("Excel export error:", message);
|
exportLogger.error(`export failed · dur=${dur}ms · ${formatError(err)}`);
|
||||||
return NextResponse.json({ error: message }, { status: 500 });
|
return NextResponse.json({ error: message }, { status: 500 });
|
||||||
} finally {
|
} finally {
|
||||||
if (pool) {
|
if (pool) {
|
||||||
|
|||||||
Reference in New Issue
Block a user