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 { backgroundColors, borderColors } = require("./canvas-colors");
const { defaultsDeep, isNumber } = require("lodash"); const { defaultsDeep, isNumber } = require("lodash");
const CANVAS_QUEUE_LIMIT = 100;
let isProcessing = false; let isProcessing = false;
const requestQueue = []; const requestQueue = [];
@@ -83,9 +85,7 @@ const processCanvasRequest = async (req, res, isSkia = false) => {
const chart = new Chart(ctx, configuration); const chart = new Chart(ctx, configuration);
// Generate and send the image // Generate and send the image
const chartImage = isSkia const chartImage = isSkia ? (await canvas.toBuffer("image/png")).toString("base64") : canvas.toDataURL();
? (await canvas.toBuffer("image/png")).toString("base64")
: canvas.toDataURL();
chart.destroy(); chart.destroy();
res.status(200).send(isSkia ? `data:image/png;base64,${chartImage}` : chartImage); 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 () => { const enqueueRequest = (req, res, isSkia) => {
if (requestQueue.length === 0) { if (requestQueue.length >= CANVAS_QUEUE_LIMIT) {
isProcessing = false; res.status(503).send("Server is busy. Please try again later.");
return; 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(); const processNextInQueue = async () => {
await processCanvasRequest(req, res, isSkia); while (requestQueue.length > 0) {
processNextInQueue(); 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) { exports.canvastest = function (req, res) {
res.status(200).send("OK"); res.status(200).send("OK");
}; };
exports.canvas = async function (req, res) { exports.canvas = async (req, res) => {
if (isProcessing) { if (isProcessing || !enqueueRequest(req, res, false)) return;
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;
}
isProcessing = true; isProcessing = true;
await processCanvasRequest(req, res, false); processNextInQueue().catch((err) => console.error("canvas-processing-error", { error: err.message }));
processNextInQueue();
}; };
exports.canvasSkia = async function (req, res) { exports.canvasSkia = async (req, res) => {
if (isProcessing) { if (isProcessing || !enqueueRequest(req, res, true)) return;
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;
}
isProcessing = true; isProcessing = true;
await processCanvasRequest(req, res, true); processNextInQueue().catch((err) => console.error("canvas-processing-error", { error: err.message }));
processNextInQueue();
}; };

View File

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