0
v-firecrawl/apps/api/src/index.ts

171 lines
5.0 KiB
TypeScript
Raw Normal View History

2024-04-15 17:01:47 -04:00
import express from "express";
import bodyParser from "body-parser";
import cors from "cors";
import "dotenv/config";
import { getWebScraperQueue } from "./services/queue-service";
2024-04-20 22:04:27 -04:00
import { redisClient } from "./services/rate-limiter";
2024-04-20 19:38:05 -04:00
import { v0Router } from "./routes/v0";
2024-05-20 16:36:34 -04:00
import { initSDK } from '@hyperdx/node-opentelemetry';
2024-04-15 17:01:47 -04:00
const { createBullBoard } = require("@bull-board/api");
const { BullAdapter } = require("@bull-board/api/bullAdapter");
const { ExpressAdapter } = require("@bull-board/express");
export const app = express();
global.isProduction = process.env.IS_PRODUCTION === "true";
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json({ limit: "10mb" }));
app.use(cors()); // Add this line to enable CORS
const serverAdapter = new ExpressAdapter();
serverAdapter.setBasePath(`/admin/${process.env.BULL_AUTH_KEY}/queues`);
const { addQueue, removeQueue, setQueues, replaceQueues } = createBullBoard({
queues: [new BullAdapter(getWebScraperQueue())],
serverAdapter: serverAdapter,
});
app.use(
`/admin/${process.env.BULL_AUTH_KEY}/queues`,
serverAdapter.getRouter()
);
app.get("/", (req, res) => {
res.send("SCRAPERS-JS: Hello, world! Fly.io");
});
//write a simple test function
app.get("/test", async (req, res) => {
res.send("Hello, world!");
});
2024-04-20 19:38:05 -04:00
// register router
app.use(v0Router);
2024-04-15 17:01:47 -04:00
const DEFAULT_PORT = process.env.PORT ?? 3002;
const HOST = process.env.HOST ?? "localhost";
redisClient.connect();
2024-05-20 16:36:34 -04:00
// HyperDX OpenTelemetry
2024-05-21 21:52:46 -04:00
if(process.env.ENV === 'production') {
initSDK({ consoleCapture: true, additionalInstrumentations: []});
}
2024-05-20 16:36:34 -04:00
2024-04-21 14:27:31 -04:00
2024-04-15 17:01:47 -04:00
export function startServer(port = DEFAULT_PORT) {
const server = app.listen(Number(port), HOST, () => {
console.log(`Server listening on port ${port}`);
2024-04-20 19:38:05 -04:00
console.log(
`For the UI, open http://${HOST}:${port}/admin/${process.env.BULL_AUTH_KEY}/queues`
);
2024-04-15 17:01:47 -04:00
console.log("");
console.log("1. Make sure Redis is running on port 6379 by default");
console.log(
"2. If you want to run nango, make sure you do port forwarding in 3002 using ngrok http 3002 "
);
});
return server;
}
if (require.main === module) {
startServer();
}
2024-04-15 20:39:25 -04:00
// Use this as a "health check" that way we dont destroy the server
2024-04-15 17:01:47 -04:00
app.get(`/admin/${process.env.BULL_AUTH_KEY}/queues`, async (req, res) => {
try {
const webScraperQueue = getWebScraperQueue();
const [webScraperActive] = await Promise.all([
webScraperQueue.getActiveCount(),
]);
const noActiveJobs = webScraperActive === 0;
// 200 if no active jobs, 503 if there are active jobs
return res.status(noActiveJobs ? 200 : 500).json({
webScraperActive,
noActiveJobs,
});
} catch (error) {
console.error(error);
return res.status(500).json({ error: error.message });
}
});
app.get(`/serverHealthCheck`, async (req, res) => {
try {
const webScraperQueue = getWebScraperQueue();
2024-04-23 15:07:22 -04:00
const [waitingJobs] = await Promise.all([
webScraperQueue.getWaitingCount(),
]);
2024-04-23 15:07:22 -04:00
const noWaitingJobs = waitingJobs === 0;
// 200 if no active jobs, 503 if there are active jobs
2024-04-23 15:07:22 -04:00
return res.status(noWaitingJobs ? 200 : 500).json({
waitingJobs,
});
} catch (error) {
console.error(error);
return res.status(500).json({ error: error.message });
}
});
app.get('/serverHealthCheck/notify', async (req, res) => {
if (process.env.SLACK_WEBHOOK_URL) {
2024-04-23 15:07:22 -04:00
const treshold = 1; // The treshold value for the active jobs
const timeout = 60000; // 1 minute // The timeout value for the check in milliseconds
2024-04-23 15:07:22 -04:00
const getWaitingJobsCount = async () => {
const webScraperQueue = getWebScraperQueue();
2024-04-23 15:07:22 -04:00
const [waitingJobsCount] = await Promise.all([
webScraperQueue.getWaitingCount(),
]);
2024-04-23 15:07:22 -04:00
return waitingJobsCount;
};
res.status(200).json({ message: "Check initiated" });
2024-04-23 15:07:22 -04:00
const checkWaitingJobs = async () => {
try {
2024-04-23 15:07:22 -04:00
let waitingJobsCount = await getWaitingJobsCount();
if (waitingJobsCount >= treshold) {
setTimeout(async () => {
2024-04-23 15:07:22 -04:00
// Re-check the waiting jobs count after the timeout
waitingJobsCount = await getWaitingJobsCount();
if (waitingJobsCount >= treshold) {
const slackWebhookUrl = process.env.SLACK_WEBHOOK_URL;
const message = {
2024-04-23 15:07:22 -04:00
text: `⚠️ Warning: The number of active jobs (${waitingJobsCount}) has exceeded the threshold (${treshold}) for more than ${timeout/60000} minute(s).`,
};
const response = await fetch(slackWebhookUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(message),
})
if (!response.ok) {
console.error('Failed to send Slack notification')
}
}
}, timeout);
}
} catch (error) {
console.error(error);
}
};
2024-04-23 15:07:22 -04:00
checkWaitingJobs();
}
});
2024-04-15 17:01:47 -04:00
app.get("/is-production", (req, res) => {
res.send({ isProduction: global.isProduction });
});