Backend Development 8 min read

High‑Performance Image Generation Service Using Puppeteer with Connection Pool and Parameter Optimization

This article describes how a content‑heavy company built a scalable, high‑quality image generation service for its app by leveraging Puppeteer, a custom connection‑pool implementation, CDN caching, launch‑argument tuning, and performance monitoring to achieve low latency and high throughput.

Liulishuo Tech Team
Liulishuo Tech Team
Liulishuo Tech Team
High‑Performance Image Generation Service Using Puppeteer with Connection Pool and Parameter Optimization

Background

FluentTalk, a content‑driven company, needed an efficient way to generate high‑quality images for its English‑learning app, as images are the most direct and widely used content format across channels, commercial conversion, and sharing.

Technical Solution Choice

The team selected the widely used Puppeteer library, a Node.js API from Google that can control a headless Chrome browser to capture screenshots, which fits the requirement for server‑side image rendering.

Challenges

1. Providing a stable, high‑performance image service directly to end‑users on mobile devices. 2. Aligning the rendering approach across the app, client, and web front‑ends while convincing developers to adopt a unified solution.

Architecture Design

Images with identical parameters are cached via a CDN, reducing load on the rendering service. The system also includes a custom connection pool built with generic-pool to reuse Puppeteer browser instances.

// Connection pool initialization
public async init(): Promise
{
  const self = this;
  this.client = await this.clientPrms;
  if (!this.pool) {
    this.pool = genericPool.createPool(
      {
        create(): Promise
{ return self.createClient(); },
        destroy(client: puppeteer.Browser): Promise
{ return client.close(); },
      },
      {
        min: this.min,
        max: this.max,
        acquireTimeoutMillis: config.pagePool.acquireTimeout,
        idleTimeoutMillis: config.pagePool.idleTimeout,
        evictionRunIntervalMillis: config.pagePool.evictionTimeout,
        autostart: true,
      }
    );
  }
}
// Release resources for others to use
public async releaseClient(client: puppeteer.Browser): Promise
{
  const memory = process.memoryUsage();
  const memoryMB = memory.heapUsed / 1024 / 1024;
  const gcThreshold = process.env.GC_THRESHOLD || 1500;
  Logger.info('now memoryMB: ' + memory.heapUsed / 1024 / 1024);
  Logger.info('now pool number: ' + this.pool.size);
  // If memory usage exceeds the threshold, drain the pool
  if (memoryMB > Number(gcThreshold)) {
    this.drain();
  } else {
    const pages = await client.pages();
    await Promise.all(pages.map(page => page.close()));
    this.pool.release(client);
  }
}

Puppeteer Parameter Optimization

By tweaking launch arguments, the team achieved roughly a 30% performance boost.

this.launchArgs = {
  // https://peter.sh/experiments/chromium-command-line-switches/
  args: [
    '--no-sandbox',            // disable sandbox
    '--disable-setuid-sandbox',// disable Linux sandbox
    '--disable-gpu',           // turn off GPU acceleration
    '--no-first-run',          // skip first‑run tasks
    '--no-zygote',             // disable forked processes
    '--single-process',       // render in a single process
    '--disable-dev-shm-usage' // improve performance in Docker
  ].concat([]),
};

After optimization, single‑render latency dropped from around 2 seconds to about 1 second, and with ~50% cache hit rate a single 4‑core, 4 GB machine can handle 5‑10 QPS.

Solution Comparison

The team compared the traditional Canvas/client‑side rendering with their server‑side Puppeteer approach across dimensions such as code size, readability, reusability, compatibility (mini‑programs, H5), font handling, and resource loading. The server‑side method consistently scored better, eliminating client‑side compatibility issues and reducing bundle size.

Adopted Cases

Most of the company’s front‑end business has already integrated the service, as shown in the internal screenshots.

Performance Monitoring

A simple dashboard tracks the latency and success rate of each team’s integration, helping identify regressions early.

Platform Tools

To avoid repetitive manual design work, the team built a template‑driven image generation tool. Designers can create templates in Figma, which are then converted into React components automatically, minimizing maintenance overhead.

Future Work

1. Further performance gains, e.g., adding Redis caching and rendering templates locally to cut HTTP requests. 2. Scaling the service into a Puppeteer cluster for horizontal expansion. 3. Extending the pipeline to include content search and preprocessing to reduce upstream effort.

Authors

• Zhang Chun – Front‑end developer at FluentTalk (joined 2019). • Guo Shuaibing – Front‑end developer at FluentTalk (joined 2017), responsible for mini‑program and commercial front‑end development.

performance optimizationpuppeteerNode.jsConnection PoolImage Rendering
Liulishuo Tech Team
Written by

Liulishuo Tech Team

Help everyone become a global citizen!

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.