File size: 2,001 Bytes
0e14acb
 
3e9069b
 
 
0e14acb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3e9069b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0e14acb
 
 
 
 
 
3e9069b
 
0e14acb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
import app from "./app";
import { logger } from "./lib/logger";
import { db } from "@workspace/db";
import { conversionsTable, filesTable } from "@workspace/db";
import { eq, inArray, and, or } from "drizzle-orm";

const rawPort = process.env["PORT"];

if (!rawPort) {
  throw new Error(
    "PORT environment variable is required but was not provided.",
  );
}

const port = Number(rawPort);

if (Number.isNaN(port) || port <= 0) {
  throw new Error(`Invalid PORT value: "${rawPort}"`);
}

async function cleanupStuckJobs() {
  try {
    const stuckStatuses = ["queued", "analyzing", "routing", "ocr", "layout", "scoring", "merging", "cleanup"] as const;

    const stuckConversions = await db.query.conversionsTable.findMany({
      where: inArray(conversionsTable.status, stuckStatuses as any),
    });

    if (stuckConversions.length === 0) return;

    logger.info({ count: stuckConversions.length }, "Marking stuck conversions as failed on startup");

    for (const conv of stuckConversions) {
      await db.update(conversionsTable)
        .set({
          status: "failed",
          errorMessage: "انقطعت المعالجة بسبب إعادة تشغيل الخادم — يرجى المحاولة مجدداً",
          completedAt: new Date(),
        })
        .where(eq(conversionsTable.id, conv.id));

      if (conv.fileId) {
        await db.update(filesTable)
          .set({ status: "failed", updatedAt: new Date() })
          .where(and(
            eq(filesTable.id, conv.fileId),
            inArray(filesTable.status, ["queued", "processing"] as any),
          ));
      }
    }

    logger.info({ count: stuckConversions.length }, "Startup cleanup complete");
  } catch (err) {
    logger.error({ err }, "Startup cleanup failed — continuing anyway");
  }
}

app.listen(port, async (err) => {
  if (err) {
    logger.error({ err }, "Error listening on port");
    process.exit(1);
  }

  logger.info({ port }, "Server listening");

  await cleanupStuckJobs();
});