2
0
Эх сурвалжийг харах

Merge pull request #10516 from growilabs/feat/174344-174345-enable-puppeteer-config-from-env-var

feat(pdf-converter): Enable puppeteer-cluster config of pdf-converter from env var
Yuki Takei 4 сар өмнө
parent
commit
b350bf822e

+ 1 - 0
apps/pdf-converter/.env

@@ -1 +1,2 @@
 PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium
+PUPPETEER_CLUSTER_CONFIG={"maxConcurrency":1, "concurrency": 2}

+ 2 - 2
apps/pdf-converter/docker/README.md

@@ -5,10 +5,10 @@ GROWI PDF Converter Official docker image
 [![Node CI for pdf-converter](https://github.com/growilabs/growi/actions/workflows/ci-pdf-converter.yml/badge.svg)](https://github.com/growilabs/growi/actions/workflows/ci-pdf-converter.yml) [![docker-pulls](https://img.shields.io/docker/pulls/growilabs/pdf-converter.svg)](https://hub.docker.com/r/growilabs/pdf-converter/)
 
 
-Supported tags and respective Dockerfile links
+Dockerfile link
 ------------------------------------------------
 
-* [`1.0.0`, `latest` (Dockerfile)](https://github.com/growilabs/growi/blob/master/apps/pdf-converter/docker/Dockerfile)
+https://github.com/growilabs/growi/blob/master/apps/pdf-converter/docker/Dockerfile
 
 
 What is GROWI PDF Converter used for?

+ 1 - 1
apps/pdf-converter/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@growi/pdf-converter",
-  "version": "1.1.3-RC.0",
+  "version": "1.2.0",
   "main": "dist/index.js",
   "types": "dist/index.d.ts",
   "license": "MIT",

+ 48 - 11
apps/pdf-converter/src/service/pdf-convert.ts

@@ -5,6 +5,7 @@ import { pipeline as pipelinePromise } from 'node:stream/promises';
 import { OnInit } from '@tsed/common';
 import { Service } from '@tsed/di';
 import { Logger } from '@tsed/logger';
+import type { PuppeteerNodeLaunchOptions } from 'puppeteer';
 import { Cluster } from 'puppeteer-cluster';
 
 interface PageInfo {
@@ -37,8 +38,6 @@ interface JobInfo {
 class PdfConvertService implements OnInit {
   private puppeteerCluster: Cluster | undefined;
 
-  private maxConcurrency = 1;
-
   private convertRetryLimit = 5;
 
   private tmpOutputRootDir = '/tmp/page-bulk-export';
@@ -292,15 +291,8 @@ class PdfConvertService implements OnInit {
   private async initPuppeteerCluster(): Promise<void> {
     if (process.env.SKIP_PUPPETEER_INIT === 'true') return;
 
-    this.puppeteerCluster = await Cluster.launch({
-      concurrency: Cluster.CONCURRENCY_PAGE,
-      maxConcurrency: this.maxConcurrency,
-      workerCreationDelay: 10000,
-      puppeteerOptions: {
-        // ref) https://github.com/growilabs/growi/pull/10192
-        args: ['--no-sandbox'],
-      },
-    });
+    const config = this.getPuppeteerClusterConfig();
+    this.puppeteerCluster = await Cluster.launch(config);
 
     await this.puppeteerCluster.task(async ({ page, data: htmlString }) => {
       await page.setContent(htmlString, { waitUntil: 'domcontentloaded' });
@@ -326,6 +318,51 @@ class PdfConvertService implements OnInit {
     });
   }
 
+  /**
+   * Get puppeteer cluster configuration from environment variable
+   * @returns merged cluster configuration
+   */
+  private getPuppeteerClusterConfig(): Record<string, any> {
+    // Default cluster configuration
+    const defaultConfig = {
+      concurrency: Cluster.CONCURRENCY_CONTEXT,
+      maxConcurrency: 1,
+      workerCreationDelay: 10000,
+      // Puppeteer options (not configurable for security reasons)
+      // ref) https://github.com/growilabs/growi/pull/10192
+      puppeteerOptions: {
+        args: ['--no-sandbox'],
+      },
+    };
+
+    // Parse configuration from environment variable
+    let customConfig: Record<string, any> = {};
+    if (process.env.PUPPETEER_CLUSTER_CONFIG) {
+      try {
+        customConfig = JSON.parse(process.env.PUPPETEER_CLUSTER_CONFIG);
+      } catch (err) {
+        this.logger.warn(
+          'Failed to parse PUPPETEER_CLUSTER_CONFIG, using default values',
+          err,
+        );
+      }
+    }
+
+    // Remove puppeteerOptions from custom config if present (not allowed for security)
+    if (customConfig.puppeteerOptions) {
+      this.logger.warn(
+        'puppeteerOptions configuration is not allowed for security reasons and will be ignored',
+      );
+      delete customConfig.puppeteerOptions;
+    }
+
+    // Merge configurations (customConfig overrides defaultConfig, except puppeteerOptions)
+    return {
+      ...defaultConfig,
+      ...customConfig,
+    };
+  }
+
   /**
    * Get parent path from given path
    * @param path target path