oven-sh / bun

Incredibly fast JavaScript runtime, bundler, test runner, and package manager – all in one
https://bun.sh
Other
72.83k stars 2.64k forks source link

async @napi-rs/canvas crashes under load #12375

Closed 7f8ddd closed 1 month ago

7f8ddd commented 1 month ago

How can we reproduce the crash?

bun i @napi-rs/canvas

import { createCanvas } from "@napi-rs/canvas";

async function generate() {
  const canvas = createCanvas(400, 200);
  const ctx = canvas.getContext("2d");

  ctx.fillStyle = "#FFFFFF";
  ctx.fillRect(0, 0, canvas.width, canvas.height);

  const encoded = await canvas.encode("webp");

  return `data:image/webp;base64,${encoded.toString("base64")}`;
}

while (true) {
  generate();
}

Relevant log output

No response

Stack Trace (bun.report)

Bun v1.1.18 (ee25618) on linux x86_64 [RunCommand]

Segmentation fault at address 0x63DDD711F

7f8ddd commented 1 month ago

This causes things like captcha generation or Discord bot image generation to randomly crash when under load. By load, I mean around 1000 rq/s or less.

Adding a Bun.sleepSync(1) is how I temporarily resolved the problem.

It may be even less rq/s if the encode takes longer.

Jarred-Sumner commented 1 month ago

This is a bug in napi-rs. The same code segfaults in Node if you add a short delay every N runs.

import { createCanvas } from "@napi-rs/canvas";

async function generate() {
  const canvas = createCanvas(400, 200);
  const ctx = canvas.getContext("2d");

  ctx.fillStyle = "#FFFFFF";
  ctx.fillRect(0, 0, canvas.width, canvas.height);

  const encoded = await canvas.encode("webp");

  return `data:image/webp;base64,${encoded.toString("base64")}`;
}

while (true) {
  const promises = [];
  for (let i = 0; i < 1000; i++) {
    promises.push(generate());
  }
  const images = await Promise.all(promises);
}

The crash in Bun happens earlier because we run the finalizers without delaying to the setImmediate task queue. The crash occurs because the context pointer passed to the finalizer is no longer valid.

I suggest opening an issue in @napi-rs/canvas to address this. It may be a bug in napi-rs itself, it's a little unclear.