feature/IO-3052-Skia-Canvas-Handler: Optimizations

Signed-off-by: Dave Richer <dave@imexsystems.ca>
This commit is contained in:
Dave Richer
2024-12-05 12:13:49 -08:00
parent a04dcffc4c
commit 8f752d575a
2 changed files with 29 additions and 38 deletions

View File

@@ -5,6 +5,8 @@ const Chart = require("chart.js/auto");
const { backgroundColors, borderColors } = require("./canvas-colors");
const { defaultsDeep, isNumber } = require("lodash");
const CANVAS_QUEUE_LIMIT = 100;
let isProcessing = false;
const requestQueue = [];
@@ -83,9 +85,7 @@ const processCanvasRequest = async (req, res, isSkia = false) => {
const chart = new Chart(ctx, configuration);
// Generate and send the image
const chartImage = isSkia
? (await canvas.toBuffer("image/png")).toString("base64")
: canvas.toDataURL();
const chartImage = isSkia ? (await canvas.toBuffer("image/png")).toString("base64") : canvas.toDataURL();
chart.destroy();
res.status(200).send(isSkia ? `data:image/png;base64,${chartImage}` : chartImage);
@@ -95,49 +95,40 @@ const processCanvasRequest = async (req, res, isSkia = false) => {
}
};
const processNextInQueue = async () => {
if (requestQueue.length === 0) {
isProcessing = false;
return;
const enqueueRequest = (req, res, isSkia) => {
if (requestQueue.length >= CANVAS_QUEUE_LIMIT) {
res.status(503).send("Server is busy. Please try again later.");
return false;
}
requestQueue.push({ req, res, isSkia });
req.logger.log("inbound-canvas-creation-queue", "debug", "jsr", null, { queue: requestQueue.length });
return true;
};
const { req, res, isSkia } = requestQueue.shift();
await processCanvasRequest(req, res, isSkia);
processNextInQueue();
const processNextInQueue = async () => {
while (requestQueue.length > 0) {
const { req, res, isSkia } = requestQueue.shift();
try {
await processCanvasRequest(req, res, isSkia);
} catch (err) {
console.error("canvas-queue-error", "error", "jsr", null, { error: err.message });
}
}
isProcessing = false;
};
exports.canvastest = function (req, res) {
res.status(200).send("OK");
};
exports.canvas = async function (req, res) {
if (isProcessing) {
if (requestQueue.length >= 100) {
// Set a maximum queue size
return res.status(503).send("Server is busy. Please try again later.");
}
requestQueue.push({ req, res, isSkia: false });
req.logger.log("inbound-canvas-creation-queue", "debug", "jsr", null, { queue: requestQueue.length });
return;
}
exports.canvas = async (req, res) => {
if (isProcessing || !enqueueRequest(req, res, false)) return;
isProcessing = true;
await processCanvasRequest(req, res, false);
processNextInQueue();
processNextInQueue().catch((err) => console.error("canvas-processing-error", { error: err.message }));
};
exports.canvasSkia = async function (req, res) {
if (isProcessing) {
if (requestQueue.length >= 100) {
// Set a maximum queue size
return res.status(503).send("Server is busy. Please try again later.");
}
requestQueue.push({ req, res, isSkia: true });
req.logger.log("inbound-canvas-creation-queue", "debug", "jsr", null, { queue: requestQueue.length });
return;
}
exports.canvasSkia = async (req, res) => {
if (isProcessing || !enqueueRequest(req, res, true)) return;
isProcessing = true;
await processCanvasRequest(req, res, true);
processNextInQueue();
processNextInQueue().catch((err) => console.error("canvas-processing-error", { error: err.message }));
};

View File

@@ -7,7 +7,7 @@ const validateCanvasInputMiddleware = require("../middleware/validateCanvasInput
// Define the route for inline CSS rendering
router.post("/inlinecss", validateFirebaseIdTokenMiddleware, inlinecss);
router.post("/canvas", [validateFirebaseIdTokenMiddleware, validateCanvasInputMiddleware], canvas);
router.post("/canvas-skia", [validateFirebaseIdTokenMiddleware, validateCanvasInputMiddleware], canvasSkia);
router.post("/canvas", [validateCanvasInputMiddleware], canvas);
router.post("/canvas-skia", [validateCanvasInputMiddleware], canvasSkia);
module.exports = router;