@remotion/lambda 4.0.8 → 4.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -26,7 +26,9 @@ const getCompositionsOnLambda = async ({ chromiumOptions, serveUrl, region, inpu
26
26
  region,
27
27
  userSpecifiedBucketName: bucketName !== null && bucketName !== void 0 ? bucketName : null,
28
28
  propsType: 'input-props',
29
- needsToUpload: (0, compress_props_1.getNeedsToUpload)('video-or-audio', stringifiedInputProps),
29
+ needsToUpload: (0, compress_props_1.getNeedsToUpload)('video-or-audio', [
30
+ stringifiedInputProps.length,
31
+ ]),
30
32
  });
31
33
  try {
32
34
  const res = await (0, call_lambda_1.callLambda)({
@@ -23,7 +23,9 @@ const makeLambdaRenderMediaPayload = async ({ rendererFunctionName, frameRange,
23
23
  const serialized = await (0, compress_props_1.compressInputProps)({
24
24
  stringifiedInputProps,
25
25
  region,
26
- needsToUpload: (0, compress_props_1.getNeedsToUpload)('video-or-audio', stringifiedInputProps),
26
+ needsToUpload: (0, compress_props_1.getNeedsToUpload)('video-or-audio', [
27
+ stringifiedInputProps.length,
28
+ ]),
27
29
  userSpecifiedBucketName: bucketName !== null && bucketName !== void 0 ? bucketName : null,
28
30
  propsType: 'input-props',
29
31
  });
@@ -31,7 +31,7 @@ const renderStillOnLambda = async ({ functionName, serveUrl, inputProps, imageFo
31
31
  const serializedInputProps = await (0, compress_props_1.compressInputProps)({
32
32
  stringifiedInputProps,
33
33
  region,
34
- needsToUpload: (0, compress_props_1.getNeedsToUpload)('still', stringifiedInputProps),
34
+ needsToUpload: (0, compress_props_1.getNeedsToUpload)('still', [stringifiedInputProps.length]),
35
35
  userSpecifiedBucketName: forceBucketName !== null && forceBucketName !== void 0 ? forceBucketName : null,
36
36
  propsType: 'input-props',
37
37
  });
@@ -191,7 +191,12 @@ const innerLaunchHandler = async (params, options) => {
191
191
  const sortedChunks = chunks.slice().sort((a, b) => a[0] - b[0]);
192
192
  const reqSend = (0, timer_1.timer)('sending off requests');
193
193
  const serializedResolved = (0, compress_props_1.serializeOrThrow)(comp.props, 'resolved-props');
194
- const needsToUpload = (0, compress_props_1.getNeedsToUpload)('video-or-audio', serializedResolved + params.inputProps);
194
+ const needsToUpload = (0, compress_props_1.getNeedsToUpload)('video-or-audio', [
195
+ serializedResolved.length,
196
+ params.inputProps.type === 'bucket-url'
197
+ ? params.inputProps.hash.length
198
+ : params.inputProps.payload.length,
199
+ ]);
195
200
  const serializedResolvedProps = await (0, compress_props_1.compressInputProps)({
196
201
  propsType: 'resolved-props',
197
202
  region: (0, get_current_region_1.getCurrentRegionInFunction)(),
@@ -368,7 +373,14 @@ const innerLaunchHandler = async (params, options) => {
368
373
  else {
369
374
  console.log('No webhook specified');
370
375
  }
371
- throw new Error('Stopping Lambda function because error occurred: ' + errors[0].stack);
376
+ const firstError = errors[0];
377
+ if (firstError.chunk !== null) {
378
+ throw new Error(`Stopping Lambda function because error occurred while rendering chunk ${firstError.chunk}:\n${errors[0].stack
379
+ .split('\n')
380
+ .map((s) => ` ${s}`)
381
+ .join('\n')}`);
382
+ }
383
+ throw new Error(`Stopping Lambda function because error occurred: ${errors[0].stack}`);
372
384
  };
373
385
  const fps = comp.fps / params.everyNthFrame;
374
386
  const outdir = (0, node_path_1.join)(renderer_1.RenderInternals.tmpDir(constants_1.CONCAT_FOLDER_TOKEN), 'bucket');
@@ -79,9 +79,8 @@ const renderHandler = async (params, options, logs) => {
79
79
  serializedInputPropsWithCustomSchema,
80
80
  frameRange: params.frameRange,
81
81
  onProgress: ({ renderedFrames, encodedFrames, stitchStage }) => {
82
- if (renderedFrames % 5 === 0 &&
83
- renderer_1.RenderInternals.isEqualOrBelowLogLevel(params.logLevel, 'verbose')) {
84
- console.log(`Rendered ${renderedFrames} frames, encoded ${encodedFrames} frames, stage = ${stitchStage}`);
82
+ if (renderedFrames % 5 === 0) {
83
+ renderer_1.RenderInternals.Log.info(`Rendered ${renderedFrames} frames, encoded ${encodedFrames} frames, stage = ${stitchStage}`);
85
84
  (0, chunk_progress_1.writeLambdaInitializedFile)({
86
85
  attempt: params.attempt,
87
86
  bucketName: params.bucketName,
@@ -90,10 +89,13 @@ const renderHandler = async (params, options, logs) => {
90
89
  framesRendered: renderedFrames,
91
90
  renderId: params.renderId,
92
91
  }).catch((err) => {
93
- console.log(err);
92
+ console.log('Could not write progress', err);
94
93
  return reject(err);
95
94
  });
96
95
  }
96
+ else {
97
+ renderer_1.RenderInternals.Log.verbose(`Rendered ${renderedFrames} frames, encoded ${encodedFrames} frames, stage = ${stitchStage}`);
98
+ }
97
99
  const allFrames = renderer_1.RenderInternals.getFramesToRender(params.frameRange, params.everyNthFrame);
98
100
  if (renderedFrames === allFrames.length) {
99
101
  console.log('Rendered all frames!');
@@ -242,11 +244,14 @@ const rendererHandler = async (params, options) => {
242
244
  }
243
245
  // If this error is encountered, we can just retry as it
244
246
  // is a very rare error to occur
245
- const isBrowserError = err.message.includes('FATAL:zygote_communication_linux.cc') ||
246
- err.message.includes('error while loading shared libraries: libnss3.so');
247
+ const isRetryableError = err.message.includes('FATAL:zygote_communication_linux.cc') ||
248
+ err.message.includes('error while loading shared libraries: libnss3.so') ||
249
+ err.message.includes('but the server sent no data') ||
250
+ err.message.includes('Timed out while setting up the headless browser');
247
251
  const shouldNotRetry = err.name === 'CancelledError';
248
- const willRetry = (isBrowserError || params.retriesLeft > 0) && !shouldNotRetry;
249
- console.log('Error occurred');
252
+ const isFatal = !isRetryableError;
253
+ const willRetry = isRetryableError && params.retriesLeft > 0 && !shouldNotRetry;
254
+ console.log(`Error occurred (will retry = ${String(willRetry)})`);
250
255
  console.log(err);
251
256
  await (0, write_lambda_error_1.writeLambdaError)({
252
257
  bucketName: params.bucketName,
@@ -257,7 +262,7 @@ const rendererHandler = async (params, options) => {
257
262
  chunk: params.chunk,
258
263
  frame: null,
259
264
  type: 'renderer',
260
- isFatal: !isBrowserError,
265
+ isFatal,
261
266
  tmpDir: (0, write_lambda_error_1.getTmpDirStateIfENoSp)(err.stack),
262
267
  attempt: params.attempt,
263
268
  totalAttempts: params.retriesLeft + params.attempt,
@@ -2,7 +2,7 @@ import type { AwsRegion } from '../client';
2
2
  import type { SerializedInputProps } from './constants';
3
3
  type PropsType = 'input-props' | 'resolved-props';
4
4
  export declare const serializeOrThrow: (inputProps: Record<string, unknown>, propsType: PropsType) => string;
5
- export declare const getNeedsToUpload: (type: 'still' | 'video-or-audio', stringifiedInputProps: string) => boolean;
5
+ export declare const getNeedsToUpload: (type: 'still' | 'video-or-audio', sizes: number[]) => boolean;
6
6
  export declare const compressInputProps: ({ stringifiedInputProps, region, userSpecifiedBucketName, propsType, needsToUpload, }: {
7
7
  stringifiedInputProps: string;
8
8
  region: AwsRegion;
@@ -21,10 +21,12 @@ const serializeOrThrow = (inputProps, propsType) => {
21
21
  }
22
22
  };
23
23
  exports.serializeOrThrow = serializeOrThrow;
24
- const getNeedsToUpload = (type, stringifiedInputProps) => {
25
- const MAX_INLINE_PAYLOAD_SIZE = type === 'still' ? 5000000 : 200000;
26
- if (stringifiedInputProps.length > MAX_INLINE_PAYLOAD_SIZE) {
27
- console.warn(`Warning: The props are over ${Math.round(MAX_INLINE_PAYLOAD_SIZE / 1000)}KB (${Math.ceil(stringifiedInputProps.length / 1024)}KB) in size. Uploading them to S3 to circumvent AWS Lambda payload size, which may lead to slowdown.`);
24
+ const getNeedsToUpload = (type, sizes) => {
25
+ const MARGIN = 5000;
26
+ const MAX_INLINE_PAYLOAD_SIZE = (type === 'still' ? 5000000 : 200000) - MARGIN;
27
+ const sizesAlreadyUsed = sizes.reduce((a, b) => a + b);
28
+ if (sizesAlreadyUsed > MAX_INLINE_PAYLOAD_SIZE) {
29
+ console.warn(`Warning: The props are over ${Math.round(MAX_INLINE_PAYLOAD_SIZE / 1000)}KB (${Math.ceil(sizesAlreadyUsed / 1024)}KB) in size. Uploading them to S3 to circumvent AWS Lambda payload size, which may lead to slowdown.`);
28
30
  return true;
29
31
  }
30
32
  return false;
@@ -38,9 +38,10 @@ export declare const mockableHttpClients: {
38
38
  http: typeof http.request;
39
39
  https: typeof https.request;
40
40
  };
41
- export declare function invokeWebhook({ payload, secret, url, }: {
41
+ type InvokeWebhookOptions = {
42
42
  payload: WebhookPayload;
43
43
  url: string;
44
44
  secret: string | null;
45
- }): Promise<void>;
45
+ };
46
+ export declare const invokeWebhook: (options: InvokeWebhookOptions, retries?: number, errors?: number) => Promise<void>;
46
47
  export {};
@@ -27,6 +27,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
27
27
  };
28
28
  Object.defineProperty(exports, "__esModule", { value: true });
29
29
  exports.invokeWebhook = exports.mockableHttpClients = exports.calculateSignature = void 0;
30
+ const renderer_1 = require("@remotion/renderer");
30
31
  const https_1 = __importDefault(require("https"));
31
32
  const Crypto = __importStar(require("node:crypto"));
32
33
  const node_http_1 = __importDefault(require("node:http"));
@@ -59,7 +60,7 @@ exports.mockableHttpClients = {
59
60
  http: node_http_1.default.request,
60
61
  https: https_1.default.request,
61
62
  };
62
- function invokeWebhook({ payload, secret, url, }) {
63
+ function invokeWebhookRaw({ payload, secret, url, }) {
63
64
  const jsonPayload = JSON.stringify(payload);
64
65
  return new Promise((resolve, reject) => {
65
66
  const req = getWebhookClient(url)(url, {
@@ -86,4 +87,26 @@ function invokeWebhook({ payload, secret, url, }) {
86
87
  req.end();
87
88
  });
88
89
  }
90
+ function exponentialBackoff(errorCount) {
91
+ return 1000 * 2 ** (errorCount - 1);
92
+ }
93
+ const invokeWebhook = async (options, retries = 2, errors = 0) => {
94
+ try {
95
+ await invokeWebhookRaw(options);
96
+ }
97
+ catch (err) {
98
+ if (retries === 0) {
99
+ throw err;
100
+ }
101
+ renderer_1.RenderInternals.Log.error('Could not send webhook due to error:');
102
+ renderer_1.RenderInternals.Log.error(err.stack);
103
+ renderer_1.RenderInternals.Log.error(`Retrying in ${exponentialBackoff(errors)}ms.`);
104
+ await new Promise((resolve) => {
105
+ setTimeout(() => {
106
+ resolve();
107
+ }, exponentialBackoff(errors));
108
+ });
109
+ return (0, exports.invokeWebhook)(options, retries - 1, errors + 1);
110
+ }
111
+ };
89
112
  exports.invokeWebhook = invokeWebhook;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remotion/lambda",
3
- "version": "4.0.8",
3
+ "version": "4.0.11",
4
4
  "description": "Distributed renderer for Remotion based on AWS Lambda",
5
5
  "main": "dist/index.js",
6
6
  "sideEffects": false,
@@ -26,10 +26,10 @@
26
26
  "aws-policies": "^1.0.1",
27
27
  "mime-types": "2.1.34",
28
28
  "zod": "3.21.4",
29
- "@remotion/bundler": "4.0.8",
30
- "@remotion/renderer": "4.0.8",
31
- "remotion": "4.0.8",
32
- "@remotion/cli": "4.0.8"
29
+ "@remotion/cli": "4.0.11",
30
+ "@remotion/renderer": "4.0.11",
31
+ "@remotion/bundler": "4.0.11",
32
+ "remotion": "4.0.11"
33
33
  },
34
34
  "devDependencies": {
35
35
  "@jonny/eslint-config": "3.0.266",
@@ -44,11 +44,11 @@
44
44
  "typescript": "4.9.5",
45
45
  "vitest": "0.31.1",
46
46
  "zip-lib": "^0.7.2",
47
- "@remotion/bundler": "4.0.8",
48
- "@remotion/compositor-linux-arm64-gnu": "4.0.8"
47
+ "@remotion/bundler": "4.0.11",
48
+ "@remotion/compositor-linux-arm64-gnu": "4.0.11"
49
49
  },
50
50
  "peerDependencies": {
51
- "@remotion/bundler": "4.0.8"
51
+ "@remotion/bundler": "4.0.11"
52
52
  },
53
53
  "publishConfig": {
54
54
  "access": "public"
Binary file