mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
# Backport This will backport the following commits from `main` to `8.16`: - [[Screenshotting/PDF Worker Thread] Add type to GeneratePdfResponse (#196860)](https://github.com/elastic/kibana/pull/196860) <!--- Backport version: 9.4.3 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sqren/backport) <!--BACKPORT [{"author":{"name":"Krzysztof Kowalczyk","email":"krzysztof.kowalczyk@elastic.co"},"sourceCommit":{"committedDate":"2024-10-21T19:15:58Z","message":"[Screenshotting/PDF Worker Thread] Add type to GeneratePdfResponse (#196860)\n\n## Summary\r\n\r\nThis PR adds a `type` to `GeneratePdfResponse` and introduces more\r\nlogging for PDF worker.\r\n\r\nCloses: #194493","sha":"c25a97bc0a3a85ad5c7bb18aab7916410efd05b7","branchLabelMapping":{"^v9.0.0$":"main","^v8.17.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","v9.0.0","Team:SharedUX","v8.16.0","Feature:Reporting:Screenshot","backport:version","v8.17.0"],"title":"[Screenshotting/PDF Worker Thread] Add type to GeneratePdfResponse","number":196860,"url":"https://github.com/elastic/kibana/pull/196860","mergeCommit":{"message":"[Screenshotting/PDF Worker Thread] Add type to GeneratePdfResponse (#196860)\n\n## Summary\r\n\r\nThis PR adds a `type` to `GeneratePdfResponse` and introduces more\r\nlogging for PDF worker.\r\n\r\nCloses: #194493","sha":"c25a97bc0a3a85ad5c7bb18aab7916410efd05b7"}},"sourceBranch":"main","suggestedTargetBranches":["8.16","8.x"],"targetPullRequestStates":[{"branch":"main","label":"v9.0.0","branchLabelMappingKey":"^v9.0.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/196860","number":196860,"mergeCommit":{"message":"[Screenshotting/PDF Worker Thread] Add type to GeneratePdfResponse (#196860)\n\n## Summary\r\n\r\nThis PR adds a `type` to `GeneratePdfResponse` and introduces more\r\nlogging for PDF worker.\r\n\r\nCloses: #194493","sha":"c25a97bc0a3a85ad5c7bb18aab7916410efd05b7"}},{"branch":"8.16","label":"v8.16.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"8.x","label":"v8.17.0","branchLabelMappingKey":"^v8.17.0$","isSourceBranch":false,"state":"NOT_CREATED"}]}] BACKPORT--> Co-authored-by: Krzysztof Kowalczyk <krzysztof.kowalczyk@elastic.co>
This commit is contained in:
parent
68a67f34f6
commit
494164e179
2 changed files with 91 additions and 22 deletions
|
@ -22,7 +22,12 @@ import {
|
|||
} from './constants';
|
||||
import { REPORTING_TABLE_LAYOUT } from './get_doc_options';
|
||||
import { getFont } from './get_font';
|
||||
import type { GeneratePdfRequest, GeneratePdfResponse, WorkerData } from './worker';
|
||||
import {
|
||||
GeneratePdfResponseType,
|
||||
type GeneratePdfRequest,
|
||||
type WorkerData,
|
||||
GeneratePdfResponse,
|
||||
} from './worker';
|
||||
|
||||
// Ensure that all dependencies are included in the release bundle.
|
||||
import './worker_dependencies';
|
||||
|
@ -32,6 +37,8 @@ export class PdfMaker {
|
|||
private content: Content[];
|
||||
|
||||
private worker?: Worker;
|
||||
private workerLogger: Logger;
|
||||
|
||||
private pageCount: number = 0;
|
||||
private transferList: ArrayBuffer[] = [];
|
||||
|
||||
|
@ -71,6 +78,7 @@ export class PdfMaker {
|
|||
) {
|
||||
this.title = '';
|
||||
this.content = [];
|
||||
this.workerLogger = logger.get('pdf-worker');
|
||||
|
||||
// running in dist: `worker.ts` becomes `worker.js`
|
||||
// running in source: `worker_src_harness.ts` needs to be wrapped in JS and have a ts-node environment initialized.
|
||||
|
@ -209,26 +217,37 @@ export class PdfMaker {
|
|||
const { port1: myPort, port2: theirPort } = new MessageChannel();
|
||||
this.worker = this.createWorker(theirPort);
|
||||
this.worker.on('error', (workerError: NodeJS.ErrnoException) => {
|
||||
this.workerLogger.error(`Worker error: ${workerError}`);
|
||||
if (workerError.code === 'ERR_WORKER_OUT_OF_MEMORY') {
|
||||
reject(new errors.PdfWorkerOutOfMemoryError(workerError.message));
|
||||
} else {
|
||||
reject(workerError);
|
||||
}
|
||||
});
|
||||
this.worker.on('exit', () => {});
|
||||
this.worker.on('exit', () => {
|
||||
this.workerLogger.debug('Worker exited');
|
||||
});
|
||||
|
||||
// We expect one message from the worker generating the PDF buffer.
|
||||
myPort.on('message', ({ error, data }: GeneratePdfResponse) => {
|
||||
if (error) {
|
||||
myPort.on('message', ({ type, error, data, message }: GeneratePdfResponse) => {
|
||||
if (type === GeneratePdfResponseType.Log && message) {
|
||||
this.workerLogger.debug(message);
|
||||
return;
|
||||
}
|
||||
|
||||
if (type === GeneratePdfResponseType.Error) {
|
||||
reject(new Error(`PDF worker returned the following error: ${error}`));
|
||||
return;
|
||||
}
|
||||
if (!data) {
|
||||
|
||||
if (type === GeneratePdfResponseType.Data && !data) {
|
||||
reject(new Error(`Worker did not generate a PDF!`));
|
||||
return;
|
||||
}
|
||||
this.pageCount = data.metrics.pages;
|
||||
resolve(data.buffer);
|
||||
|
||||
if (data) {
|
||||
this.pageCount = data.metrics.pages;
|
||||
resolve(data.buffer);
|
||||
}
|
||||
});
|
||||
|
||||
// Send the request
|
||||
|
|
|
@ -34,23 +34,44 @@ export interface GeneratePdfRequest {
|
|||
data: GenerateReportRequestData;
|
||||
}
|
||||
|
||||
export type GeneratePdfResponse = SuccessResponse | ErrorResponse;
|
||||
|
||||
export interface SuccessResponse {
|
||||
error?: undefined;
|
||||
data: {
|
||||
buffer: Uint8Array;
|
||||
metrics: {
|
||||
pages: number;
|
||||
};
|
||||
export interface GeneratePdfData {
|
||||
buffer: Uint8Array;
|
||||
metrics: {
|
||||
pages: number;
|
||||
};
|
||||
}
|
||||
|
||||
export interface ErrorResponse {
|
||||
error: string;
|
||||
data: null;
|
||||
export enum GeneratePdfResponseType {
|
||||
Log,
|
||||
Data,
|
||||
Error,
|
||||
}
|
||||
|
||||
interface GeneratePdfLogResponse {
|
||||
type: GeneratePdfResponseType.Log;
|
||||
data?: GeneratePdfData;
|
||||
error?: string;
|
||||
message?: string;
|
||||
}
|
||||
|
||||
interface GeneratePdfDataResponse {
|
||||
type: GeneratePdfResponseType.Data;
|
||||
data?: GeneratePdfData;
|
||||
error?: string;
|
||||
message?: string;
|
||||
}
|
||||
|
||||
interface GeneratePdfErrorResponse {
|
||||
type: GeneratePdfResponseType.Error;
|
||||
data?: GeneratePdfData;
|
||||
error?: string;
|
||||
message?: string;
|
||||
}
|
||||
export type GeneratePdfResponse =
|
||||
| GeneratePdfLogResponse
|
||||
| GeneratePdfDataResponse
|
||||
| GeneratePdfErrorResponse;
|
||||
|
||||
if (!isMainThread) {
|
||||
const { port } = workerData as WorkerData;
|
||||
port.on('message', execute);
|
||||
|
@ -68,6 +89,11 @@ const getPageCount = (pdfDoc: PDFKit.PDFDocument): number => {
|
|||
|
||||
async function execute({ data: { layout, logo, title, content } }: GeneratePdfRequest) {
|
||||
const { port } = workerData as WorkerData;
|
||||
port.postMessage({
|
||||
type: GeneratePdfResponseType.Log,
|
||||
message: 'Starting execution',
|
||||
});
|
||||
|
||||
try {
|
||||
const tableBorderWidth = 1;
|
||||
|
||||
|
@ -89,6 +115,11 @@ async function execute({ data: { layout, logo, title, content } }: GeneratePdfRe
|
|||
},
|
||||
};
|
||||
|
||||
port.postMessage({
|
||||
type: GeneratePdfResponseType.Log,
|
||||
message: 'Initializing PDF printer',
|
||||
});
|
||||
|
||||
const printer = new Printer(fonts);
|
||||
|
||||
const docDefinition = _.assign(getTemplate(layout, logo, title, tableBorderWidth, assetPath), {
|
||||
|
@ -103,6 +134,11 @@ async function execute({ data: { layout, logo, title, content } }: GeneratePdfRe
|
|||
),
|
||||
});
|
||||
|
||||
port.postMessage({
|
||||
type: GeneratePdfResponseType.Log,
|
||||
message: 'Generating document stream',
|
||||
});
|
||||
|
||||
const pdfDoc = printer.createPdfKitDocument(docDefinition, {
|
||||
tableLayouts: {
|
||||
noBorder: {
|
||||
|
@ -121,6 +157,11 @@ async function execute({ data: { layout, logo, title, content } }: GeneratePdfRe
|
|||
throw new Error('Document stream has not been generated');
|
||||
}
|
||||
|
||||
port.postMessage({
|
||||
type: GeneratePdfResponseType.Log,
|
||||
message: 'Document stream has been generated',
|
||||
});
|
||||
|
||||
const buffer = await new Promise<Buffer>((resolve, reject) => {
|
||||
const buffers: Buffer[] = [];
|
||||
pdfDoc.on('error', reject);
|
||||
|
@ -133,7 +174,13 @@ async function execute({ data: { layout, logo, title, content } }: GeneratePdfRe
|
|||
pdfDoc.end();
|
||||
});
|
||||
|
||||
const successResponse: SuccessResponse = {
|
||||
port.postMessage({
|
||||
type: GeneratePdfResponseType.Log,
|
||||
message: 'PDF buffer has been generated',
|
||||
});
|
||||
|
||||
const successResponse: GeneratePdfResponse = {
|
||||
type: GeneratePdfResponseType.Data,
|
||||
data: {
|
||||
buffer,
|
||||
metrics: {
|
||||
|
@ -143,7 +190,10 @@ async function execute({ data: { layout, logo, title, content } }: GeneratePdfRe
|
|||
};
|
||||
port.postMessage(successResponse, [buffer.buffer /* Transfer buffer instead of copying */]);
|
||||
} catch (error) {
|
||||
const errorResponse: ErrorResponse = { error: error.message, data: null };
|
||||
const errorResponse: GeneratePdfResponse = {
|
||||
type: GeneratePdfResponseType.Error,
|
||||
error: error.message,
|
||||
};
|
||||
port.postMessage(errorResponse);
|
||||
} finally {
|
||||
process.nextTick(() => {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue