@remotion/lambda 4.0.16 → 4.0.18
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.
- package/dist/api/get-compositions-on-lambda.js +1 -0
- package/dist/api/get-render-progress.js +1 -0
- package/dist/api/render-media-on-lambda.js +1 -0
- package/dist/api/render-still-on-lambda.js +1 -0
- package/dist/cli/log.d.ts +4 -4
- package/dist/functions/helpers/concat-videos.d.ts +1 -1
- package/dist/functions/helpers/concat-videos.js +1 -1
- package/dist/functions/launch.js +112 -123
- package/dist/functions/renderer.js +3 -7
- package/dist/functions/still.js +3 -2
- package/dist/shared/call-lambda.d.ts +6 -2
- package/dist/shared/call-lambda.js +25 -3
- package/dist/shared/cleanup-serialized-input-props.d.ts +5 -0
- package/dist/shared/cleanup-serialized-input-props.js +15 -1
- package/dist/shared/deserialize-input-props.d.ts +8 -0
- package/dist/shared/deserialize-input-props.js +26 -0
- package/dist/shared/get-function-version.js +1 -0
- package/dist/shared/is-flaky-error.d.ts +1 -0
- package/dist/shared/is-flaky-error.js +31 -0
- package/dist/shared/serialize-input-props.d.ts +14 -0
- package/dist/shared/serialize-input-props.js +63 -0
- package/package.json +8 -9
- package/remotionlambda-arm64.zip +0 -0
package/dist/cli/log.d.ts
CHANGED
|
@@ -2,24 +2,24 @@ export declare const Log: {
|
|
|
2
2
|
verbose: (message?: any, ...optionalParams: any[]) => void;
|
|
3
3
|
verboseAdvanced: (options: {
|
|
4
4
|
indent: boolean;
|
|
5
|
-
logLevel: "
|
|
5
|
+
logLevel: "verbose" | "info" | "warn" | "error";
|
|
6
6
|
} & {
|
|
7
7
|
tag?: string | undefined;
|
|
8
8
|
}, message?: any, ...optionalParams: any[]) => void;
|
|
9
9
|
info: (message?: any, ...optionalParams: any[]) => void;
|
|
10
10
|
infoAdvanced: (options: {
|
|
11
11
|
indent: boolean;
|
|
12
|
-
logLevel: "
|
|
12
|
+
logLevel: "verbose" | "info" | "warn" | "error";
|
|
13
13
|
}, message?: any, ...optionalParams: any[]) => void;
|
|
14
14
|
warn: (message?: any, ...optionalParams: any[]) => void;
|
|
15
15
|
warnAdvanced: (options: {
|
|
16
16
|
indent: boolean;
|
|
17
|
-
logLevel: "
|
|
17
|
+
logLevel: "verbose" | "info" | "warn" | "error";
|
|
18
18
|
}, message?: any, ...optionalParams: any[]) => void;
|
|
19
19
|
error: (message?: any, ...optionalParams: any[]) => void;
|
|
20
20
|
errorAdvanced: (options: {
|
|
21
21
|
indent: boolean;
|
|
22
|
-
logLevel: "
|
|
22
|
+
logLevel: "verbose" | "info" | "warn" | "error";
|
|
23
23
|
} & {
|
|
24
24
|
tag?: string | undefined;
|
|
25
25
|
}, message?: any, ...optionalParams: any[]) => void;
|
|
@@ -9,7 +9,7 @@ export declare const getAllFilesS3: ({ bucket, expectedFiles, outdir, renderId,
|
|
|
9
9
|
renderId: string;
|
|
10
10
|
region: AwsRegion;
|
|
11
11
|
expectedBucketOwner: string;
|
|
12
|
-
onErrors: (errors: EnhancedErrorInfo[]) =>
|
|
12
|
+
onErrors: (errors: EnhancedErrorInfo[]) => void;
|
|
13
13
|
}) => Promise<string[]>;
|
|
14
14
|
export declare const concatVideosS3: ({ onProgress, numberOfFrames, codec, fps, numberOfGifLoops, files, outdir, audioCodec, }: {
|
|
15
15
|
onProgress: (frames: number) => void;
|
|
@@ -96,7 +96,7 @@ const getAllFilesS3 = ({ bucket, expectedFiles, outdir, renderId, region, expect
|
|
|
96
96
|
renderId,
|
|
97
97
|
})).filter((e) => e.isFatal);
|
|
98
98
|
if (errors.length > 0) {
|
|
99
|
-
|
|
99
|
+
onErrors(errors);
|
|
100
100
|
// Will die here
|
|
101
101
|
}
|
|
102
102
|
filesInBucket.forEach(async (key) => {
|
package/dist/functions/launch.js
CHANGED
|
@@ -89,51 +89,7 @@ const innerLaunchHandler = async (params, options) => {
|
|
|
89
89
|
}
|
|
90
90
|
const functionName = (_a = params.rendererFunctionName) !== null && _a !== void 0 ? _a : process.env.AWS_LAMBDA_FUNCTION_NAME;
|
|
91
91
|
const startedDate = Date.now();
|
|
92
|
-
let webhookInvoked = false;
|
|
93
|
-
console.log(`Function has ${Math.max(options.getRemainingTimeInMillis() - 1000, 1000)} before it times out`);
|
|
94
92
|
const verbose = renderer_1.RenderInternals.isEqualOrBelowLogLevel(params.logLevel, 'verbose');
|
|
95
|
-
const webhookDueToTimeout = setTimeout(async () => {
|
|
96
|
-
if (params.webhook && !webhookInvoked) {
|
|
97
|
-
try {
|
|
98
|
-
await (0, invoke_webhook_1.invokeWebhook)({
|
|
99
|
-
url: params.webhook.url,
|
|
100
|
-
secret: params.webhook.secret,
|
|
101
|
-
payload: {
|
|
102
|
-
type: 'timeout',
|
|
103
|
-
renderId: params.renderId,
|
|
104
|
-
expectedBucketOwner: options.expectedBucketOwner,
|
|
105
|
-
bucketName: params.bucketName,
|
|
106
|
-
},
|
|
107
|
-
});
|
|
108
|
-
webhookInvoked = true;
|
|
109
|
-
}
|
|
110
|
-
catch (err) {
|
|
111
|
-
if (process.env.NODE_ENV === 'test') {
|
|
112
|
-
throw err;
|
|
113
|
-
}
|
|
114
|
-
await (0, write_lambda_error_1.writeLambdaError)({
|
|
115
|
-
bucketName: params.bucketName,
|
|
116
|
-
errorInfo: {
|
|
117
|
-
type: 'webhook',
|
|
118
|
-
message: err.message,
|
|
119
|
-
name: err.name,
|
|
120
|
-
stack: err.stack,
|
|
121
|
-
tmpDir: null,
|
|
122
|
-
frame: 0,
|
|
123
|
-
chunk: 0,
|
|
124
|
-
isFatal: false,
|
|
125
|
-
attempt: 1,
|
|
126
|
-
willRetry: false,
|
|
127
|
-
totalAttempts: 1,
|
|
128
|
-
},
|
|
129
|
-
renderId: params.renderId,
|
|
130
|
-
expectedBucketOwner: options.expectedBucketOwner,
|
|
131
|
-
});
|
|
132
|
-
console.log('Failed to invoke webhook:');
|
|
133
|
-
console.log(err);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
}, Math.max(options.getRemainingTimeInMillis() - 1000, 1000));
|
|
137
93
|
const browserInstance = await (0, get_browser_instance_1.getBrowserInstance)(params.logLevel, false, params.chromiumOptions);
|
|
138
94
|
const inputPropsPromise = (0, compress_props_1.decompressInputProps)({
|
|
139
95
|
bucketName: params.bucketName,
|
|
@@ -245,7 +201,7 @@ const innerLaunchHandler = async (params, options) => {
|
|
|
245
201
|
};
|
|
246
202
|
return payload;
|
|
247
203
|
});
|
|
248
|
-
|
|
204
|
+
renderer_1.RenderInternals.Log.info('Render plan: ', chunks.map((c, i) => `Chunk ${i} (Frames ${c[0]} - ${c[1]})`).join(', '));
|
|
249
205
|
const renderMetadata = {
|
|
250
206
|
startedDate,
|
|
251
207
|
videoConfig: comp,
|
|
@@ -349,30 +305,8 @@ const innerLaunchHandler = async (params, options) => {
|
|
|
349
305
|
});
|
|
350
306
|
});
|
|
351
307
|
};
|
|
352
|
-
const onErrors =
|
|
353
|
-
|
|
354
|
-
console.log('Found Errors', errors);
|
|
355
|
-
if (params.webhook) {
|
|
356
|
-
console.log('Sending webhook with errors');
|
|
357
|
-
await (0, invoke_webhook_1.invokeWebhook)({
|
|
358
|
-
url: params.webhook.url,
|
|
359
|
-
secret: (_a = params.webhook.secret) !== null && _a !== void 0 ? _a : null,
|
|
360
|
-
payload: {
|
|
361
|
-
type: 'error',
|
|
362
|
-
renderId: params.renderId,
|
|
363
|
-
expectedBucketOwner: options.expectedBucketOwner,
|
|
364
|
-
bucketName: params.bucketName,
|
|
365
|
-
errors: errors.slice(0, 5).map((e) => ({
|
|
366
|
-
message: e.message,
|
|
367
|
-
name: e.name,
|
|
368
|
-
stack: e.stack,
|
|
369
|
-
})),
|
|
370
|
-
},
|
|
371
|
-
});
|
|
372
|
-
}
|
|
373
|
-
else {
|
|
374
|
-
console.log('No webhook specified');
|
|
375
|
-
}
|
|
308
|
+
const onErrors = (errors) => {
|
|
309
|
+
renderer_1.RenderInternals.Log.error('Found Errors', errors);
|
|
376
310
|
const firstError = errors[0];
|
|
377
311
|
if (firstError.chunk !== null) {
|
|
378
312
|
throw new Error(`Stopping Lambda function because error occurred while rendering chunk ${firstError.chunk}:\n${errors[0].stack
|
|
@@ -462,6 +396,11 @@ const innerLaunchHandler = async (params, options) => {
|
|
|
462
396
|
region: (0, get_current_region_1.getCurrentRegionInFunction)(),
|
|
463
397
|
serialized: params.inputProps,
|
|
464
398
|
});
|
|
399
|
+
const cleanupResolvedInputPropsProm = (0, cleanup_serialized_input_props_1.cleanupSerializedResolvedProps)({
|
|
400
|
+
bucketName: params.bucketName,
|
|
401
|
+
region: (0, get_current_region_1.getCurrentRegionInFunction)(),
|
|
402
|
+
serialized: serializedResolvedProps,
|
|
403
|
+
});
|
|
465
404
|
const outputUrl = (0, get_output_url_from_metadata_1.getOutputUrlFromMetadata)(renderMetadata, params.bucketName, customCredentials);
|
|
466
405
|
const postRenderData = (0, create_post_render_data_1.createPostRenderData)({
|
|
467
406
|
expectedBucketOwner: options.expectedBucketOwner,
|
|
@@ -472,7 +411,11 @@ const innerLaunchHandler = async (params, options) => {
|
|
|
472
411
|
contents,
|
|
473
412
|
errorExplanations: await errorExplanationsProm,
|
|
474
413
|
timeToEncode: encodingStop - encodingStart,
|
|
475
|
-
timeToDelete: (await Promise.all([
|
|
414
|
+
timeToDelete: (await Promise.all([
|
|
415
|
+
deletProm,
|
|
416
|
+
cleanupSerializedInputPropsProm,
|
|
417
|
+
cleanupResolvedInputPropsProm,
|
|
418
|
+
])).reduce((a, b) => a + b, 0),
|
|
476
419
|
outputFile: {
|
|
477
420
|
lastModified: Date.now(),
|
|
478
421
|
size: outputSize.size,
|
|
@@ -494,60 +437,104 @@ const innerLaunchHandler = async (params, options) => {
|
|
|
494
437
|
customCredentials: null,
|
|
495
438
|
});
|
|
496
439
|
await Promise.all([cleanupChunksProm, node_fs_1.default.promises.rm(outfile)]);
|
|
497
|
-
|
|
498
|
-
if (params.webhook && !webhookInvoked) {
|
|
499
|
-
try {
|
|
500
|
-
await (0, invoke_webhook_1.invokeWebhook)({
|
|
501
|
-
url: params.webhook.url,
|
|
502
|
-
secret: params.webhook.secret,
|
|
503
|
-
payload: {
|
|
504
|
-
type: 'success',
|
|
505
|
-
renderId: params.renderId,
|
|
506
|
-
expectedBucketOwner: options.expectedBucketOwner,
|
|
507
|
-
bucketName: params.bucketName,
|
|
508
|
-
outputUrl,
|
|
509
|
-
lambdaErrors: postRenderData.errors,
|
|
510
|
-
outputFile: postRenderData.outputFile,
|
|
511
|
-
timeToFinish: postRenderData.timeToFinish,
|
|
512
|
-
costs: postRenderData.cost,
|
|
513
|
-
},
|
|
514
|
-
});
|
|
515
|
-
webhookInvoked = true;
|
|
516
|
-
}
|
|
517
|
-
catch (err) {
|
|
518
|
-
if (process.env.NODE_ENV === 'test') {
|
|
519
|
-
throw err;
|
|
520
|
-
}
|
|
521
|
-
await (0, write_lambda_error_1.writeLambdaError)({
|
|
522
|
-
bucketName: params.bucketName,
|
|
523
|
-
errorInfo: {
|
|
524
|
-
type: 'webhook',
|
|
525
|
-
message: err.message,
|
|
526
|
-
name: err.name,
|
|
527
|
-
stack: err.stack,
|
|
528
|
-
tmpDir: null,
|
|
529
|
-
frame: 0,
|
|
530
|
-
chunk: 0,
|
|
531
|
-
isFatal: false,
|
|
532
|
-
attempt: 1,
|
|
533
|
-
willRetry: false,
|
|
534
|
-
totalAttempts: 1,
|
|
535
|
-
},
|
|
536
|
-
renderId: params.renderId,
|
|
537
|
-
expectedBucketOwner: options.expectedBucketOwner,
|
|
538
|
-
});
|
|
539
|
-
console.log('Failed to invoke webhook:');
|
|
540
|
-
console.log(err);
|
|
541
|
-
}
|
|
542
|
-
}
|
|
440
|
+
return postRenderData;
|
|
543
441
|
};
|
|
544
442
|
const launchHandler = async (params, options) => {
|
|
545
|
-
var _a, _b;
|
|
546
443
|
if (params.type !== constants_1.LambdaRoutines.launch) {
|
|
547
444
|
throw new Error('Expected launch type');
|
|
548
445
|
}
|
|
446
|
+
let webhookInvoked = false;
|
|
447
|
+
const webhookDueToTimeout = setTimeout(async () => {
|
|
448
|
+
if (params.webhook && !webhookInvoked) {
|
|
449
|
+
try {
|
|
450
|
+
await (0, invoke_webhook_1.invokeWebhook)({
|
|
451
|
+
url: params.webhook.url,
|
|
452
|
+
secret: params.webhook.secret,
|
|
453
|
+
payload: {
|
|
454
|
+
type: 'timeout',
|
|
455
|
+
renderId: params.renderId,
|
|
456
|
+
expectedBucketOwner: options.expectedBucketOwner,
|
|
457
|
+
bucketName: params.bucketName,
|
|
458
|
+
},
|
|
459
|
+
});
|
|
460
|
+
webhookInvoked = true;
|
|
461
|
+
}
|
|
462
|
+
catch (err) {
|
|
463
|
+
if (process.env.NODE_ENV === 'test') {
|
|
464
|
+
throw err;
|
|
465
|
+
}
|
|
466
|
+
await (0, write_lambda_error_1.writeLambdaError)({
|
|
467
|
+
bucketName: params.bucketName,
|
|
468
|
+
errorInfo: {
|
|
469
|
+
type: 'webhook',
|
|
470
|
+
message: err.message,
|
|
471
|
+
name: err.name,
|
|
472
|
+
stack: err.stack,
|
|
473
|
+
tmpDir: null,
|
|
474
|
+
frame: 0,
|
|
475
|
+
chunk: 0,
|
|
476
|
+
isFatal: false,
|
|
477
|
+
attempt: 1,
|
|
478
|
+
willRetry: false,
|
|
479
|
+
totalAttempts: 1,
|
|
480
|
+
},
|
|
481
|
+
renderId: params.renderId,
|
|
482
|
+
expectedBucketOwner: options.expectedBucketOwner,
|
|
483
|
+
});
|
|
484
|
+
renderer_1.RenderInternals.Log.error('Failed to invoke webhook:');
|
|
485
|
+
renderer_1.RenderInternals.Log.error(err);
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
}, Math.max(options.getRemainingTimeInMillis() - 1000, 1000));
|
|
489
|
+
renderer_1.RenderInternals.Log.info(`Function has ${Math.max(options.getRemainingTimeInMillis() - 1000, 1000)} before it times out`);
|
|
549
490
|
try {
|
|
550
|
-
await innerLaunchHandler(params, options);
|
|
491
|
+
const postRenderData = await innerLaunchHandler(params, options);
|
|
492
|
+
clearTimeout(webhookDueToTimeout);
|
|
493
|
+
if (params.webhook && !webhookInvoked) {
|
|
494
|
+
try {
|
|
495
|
+
await (0, invoke_webhook_1.invokeWebhook)({
|
|
496
|
+
url: params.webhook.url,
|
|
497
|
+
secret: params.webhook.secret,
|
|
498
|
+
payload: {
|
|
499
|
+
type: 'success',
|
|
500
|
+
renderId: params.renderId,
|
|
501
|
+
expectedBucketOwner: options.expectedBucketOwner,
|
|
502
|
+
bucketName: params.bucketName,
|
|
503
|
+
outputUrl: postRenderData.outputFile,
|
|
504
|
+
lambdaErrors: postRenderData.errors,
|
|
505
|
+
outputFile: postRenderData.outputFile,
|
|
506
|
+
timeToFinish: postRenderData.timeToFinish,
|
|
507
|
+
costs: postRenderData.cost,
|
|
508
|
+
},
|
|
509
|
+
});
|
|
510
|
+
webhookInvoked = true;
|
|
511
|
+
}
|
|
512
|
+
catch (err) {
|
|
513
|
+
if (process.env.NODE_ENV === 'test') {
|
|
514
|
+
throw err;
|
|
515
|
+
}
|
|
516
|
+
await (0, write_lambda_error_1.writeLambdaError)({
|
|
517
|
+
bucketName: params.bucketName,
|
|
518
|
+
errorInfo: {
|
|
519
|
+
type: 'webhook',
|
|
520
|
+
message: err.message,
|
|
521
|
+
name: err.name,
|
|
522
|
+
stack: err.stack,
|
|
523
|
+
tmpDir: null,
|
|
524
|
+
frame: 0,
|
|
525
|
+
chunk: 0,
|
|
526
|
+
isFatal: false,
|
|
527
|
+
attempt: 1,
|
|
528
|
+
willRetry: false,
|
|
529
|
+
totalAttempts: 1,
|
|
530
|
+
},
|
|
531
|
+
renderId: params.renderId,
|
|
532
|
+
expectedBucketOwner: options.expectedBucketOwner,
|
|
533
|
+
});
|
|
534
|
+
renderer_1.RenderInternals.Log.error('Failed to invoke webhook:');
|
|
535
|
+
renderer_1.RenderInternals.Log.error(err);
|
|
536
|
+
}
|
|
537
|
+
}
|
|
551
538
|
return {
|
|
552
539
|
type: 'success',
|
|
553
540
|
};
|
|
@@ -556,7 +543,7 @@ const launchHandler = async (params, options) => {
|
|
|
556
543
|
if (process.env.NODE_ENV === 'test') {
|
|
557
544
|
throw err;
|
|
558
545
|
}
|
|
559
|
-
|
|
546
|
+
renderer_1.RenderInternals.Log.error('Error occurred', err);
|
|
560
547
|
await (0, write_lambda_error_1.writeLambdaError)({
|
|
561
548
|
bucketName: params.bucketName,
|
|
562
549
|
errorInfo: {
|
|
@@ -575,11 +562,12 @@ const launchHandler = async (params, options) => {
|
|
|
575
562
|
expectedBucketOwner: options.expectedBucketOwner,
|
|
576
563
|
renderId: params.renderId,
|
|
577
564
|
});
|
|
578
|
-
|
|
565
|
+
clearTimeout(webhookDueToTimeout);
|
|
566
|
+
if (params.webhook && !webhookInvoked) {
|
|
579
567
|
try {
|
|
580
568
|
await (0, invoke_webhook_1.invokeWebhook)({
|
|
581
569
|
url: params.webhook.url,
|
|
582
|
-
secret:
|
|
570
|
+
secret: params.webhook.secret,
|
|
583
571
|
payload: {
|
|
584
572
|
type: 'error',
|
|
585
573
|
renderId: params.renderId,
|
|
@@ -592,6 +580,7 @@ const launchHandler = async (params, options) => {
|
|
|
592
580
|
})),
|
|
593
581
|
},
|
|
594
582
|
});
|
|
583
|
+
webhookInvoked = true;
|
|
595
584
|
}
|
|
596
585
|
catch (error) {
|
|
597
586
|
if (process.env.NODE_ENV === 'test') {
|
|
@@ -615,8 +604,8 @@ const launchHandler = async (params, options) => {
|
|
|
615
604
|
renderId: params.renderId,
|
|
616
605
|
expectedBucketOwner: options.expectedBucketOwner,
|
|
617
606
|
});
|
|
618
|
-
|
|
619
|
-
|
|
607
|
+
renderer_1.RenderInternals.Log.error('Failed to invoke webhook:');
|
|
608
|
+
renderer_1.RenderInternals.Log.error(error);
|
|
620
609
|
}
|
|
621
610
|
}
|
|
622
611
|
throw err;
|
|
@@ -12,6 +12,7 @@ const call_lambda_1 = require("../shared/call-lambda");
|
|
|
12
12
|
const chunk_progress_1 = require("../shared/chunk-progress");
|
|
13
13
|
const compress_props_1 = require("../shared/compress-props");
|
|
14
14
|
const constants_1 = require("../shared/constants");
|
|
15
|
+
const is_flaky_error_1 = require("../shared/is-flaky-error");
|
|
15
16
|
const get_browser_instance_1 = require("./helpers/get-browser-instance");
|
|
16
17
|
const get_chromium_executable_path_1 = require("./helpers/get-chromium-executable-path");
|
|
17
18
|
const get_current_region_1 = require("./helpers/get-current-region");
|
|
@@ -223,15 +224,9 @@ const rendererHandler = async (params, options) => {
|
|
|
223
224
|
console.log({ err });
|
|
224
225
|
throw err;
|
|
225
226
|
}
|
|
226
|
-
const { message } = err;
|
|
227
227
|
// If this error is encountered, we can just retry as it
|
|
228
228
|
// is a very rare error to occur
|
|
229
|
-
const isRetryableError =
|
|
230
|
-
message.includes('error while loading shared libraries: libnss3.so') ||
|
|
231
|
-
message.includes('but the server sent no data') ||
|
|
232
|
-
message.includes('Compositor panicked') ||
|
|
233
|
-
(message.includes('Compositor exited') && !message.includes('SIGSEGV')) ||
|
|
234
|
-
message.includes('Timed out while setting up the headless browser');
|
|
229
|
+
const isRetryableError = (0, is_flaky_error_1.isFlakyError)(err);
|
|
235
230
|
const shouldNotRetry = err.name === 'CancelledError';
|
|
236
231
|
const isFatal = !isRetryableError;
|
|
237
232
|
const willRetry = isRetryableError && params.retriesLeft > 0 && !shouldNotRetry;
|
|
@@ -268,6 +263,7 @@ const rendererHandler = async (params, options) => {
|
|
|
268
263
|
region: (0, get_current_region_1.getCurrentRegionInFunction)(),
|
|
269
264
|
receivedStreamingPayload: () => undefined,
|
|
270
265
|
timeoutInTest: 120000,
|
|
266
|
+
retriesRemaining: 0,
|
|
271
267
|
});
|
|
272
268
|
return res;
|
|
273
269
|
}
|
package/dist/functions/still.js
CHANGED
|
@@ -16,6 +16,7 @@ const cleanup_serialized_input_props_1 = require("../shared/cleanup-serialized-i
|
|
|
16
16
|
const compress_props_1 = require("../shared/compress-props");
|
|
17
17
|
const constants_1 = require("../shared/constants");
|
|
18
18
|
const convert_to_serve_url_1 = require("../shared/convert-to-serve-url");
|
|
19
|
+
const is_flaky_error_1 = require("../shared/is-flaky-error");
|
|
19
20
|
const make_s3_url_1 = require("../shared/make-s3-url");
|
|
20
21
|
const validate_download_behavior_1 = require("../shared/validate-download-behavior");
|
|
21
22
|
const validate_outname_1 = require("../shared/validate-outname");
|
|
@@ -203,8 +204,7 @@ const stillHandler = async (options) => {
|
|
|
203
204
|
catch (err) {
|
|
204
205
|
// If this error is encountered, we can just retry as it
|
|
205
206
|
// is a very rare error to occur
|
|
206
|
-
const isBrowserError =
|
|
207
|
-
err.message.includes('error while loading shared libraries: libnss3.so');
|
|
207
|
+
const isBrowserError = (0, is_flaky_error_1.isFlakyError)(err);
|
|
208
208
|
const willRetry = isBrowserError || params.maxRetries > 0;
|
|
209
209
|
if (!willRetry) {
|
|
210
210
|
throw err;
|
|
@@ -221,6 +221,7 @@ const stillHandler = async (options) => {
|
|
|
221
221
|
type: constants_1.LambdaRoutines.still,
|
|
222
222
|
receivedStreamingPayload: () => undefined,
|
|
223
223
|
timeoutInTest: 120000,
|
|
224
|
+
retriesRemaining: 0,
|
|
224
225
|
});
|
|
225
226
|
const bucketName = (_a = params.bucketName) !== null && _a !== void 0 ? _a : (await (0, get_or_create_bucket_1.getOrCreateBucket)({
|
|
226
227
|
region: (0, get_current_region_1.getCurrentRegionInFunction)(),
|
|
@@ -2,11 +2,15 @@ import type { StreamingPayloads } from '../functions/helpers/streaming-payloads'
|
|
|
2
2
|
import type { AwsRegion } from '../pricing/aws-regions';
|
|
3
3
|
import type { LambdaPayloads, LambdaRoutines } from './constants';
|
|
4
4
|
import type { LambdaReturnValues } from './return-values';
|
|
5
|
-
|
|
5
|
+
type Options<T extends LambdaRoutines> = {
|
|
6
6
|
functionName: string;
|
|
7
7
|
type: T;
|
|
8
|
-
payload: Omit<LambdaPayloads[T],
|
|
8
|
+
payload: Omit<LambdaPayloads[T], 'type'>;
|
|
9
9
|
region: AwsRegion;
|
|
10
10
|
receivedStreamingPayload: (streamPayload: StreamingPayloads) => void;
|
|
11
11
|
timeoutInTest: number;
|
|
12
|
+
};
|
|
13
|
+
export declare const callLambda: <T extends LambdaRoutines>(options: Options<T> & {
|
|
14
|
+
retriesRemaining: number;
|
|
12
15
|
}) => Promise<LambdaReturnValues[T]>;
|
|
16
|
+
export {};
|
|
@@ -4,7 +4,30 @@ exports.callLambda = void 0;
|
|
|
4
4
|
const client_lambda_1 = require("@aws-sdk/client-lambda");
|
|
5
5
|
const streaming_payloads_1 = require("../functions/helpers/streaming-payloads");
|
|
6
6
|
const aws_clients_1 = require("./aws-clients");
|
|
7
|
-
const
|
|
7
|
+
const INVALID_JSON_MESSAGE = 'Cannot parse Lambda response as JSON';
|
|
8
|
+
const callLambda = async (options) => {
|
|
9
|
+
// As of August 2023, Lambda streaming sometimes misses parts of the JSON response.
|
|
10
|
+
// Handling this for now by applying a retry mechanism.
|
|
11
|
+
try {
|
|
12
|
+
// Do not remove this await
|
|
13
|
+
const res = await callLambdaWithoutRetry(options);
|
|
14
|
+
return res;
|
|
15
|
+
}
|
|
16
|
+
catch (err) {
|
|
17
|
+
if (options.retriesRemaining === 0) {
|
|
18
|
+
throw err;
|
|
19
|
+
}
|
|
20
|
+
if (!err.message.includes(INVALID_JSON_MESSAGE)) {
|
|
21
|
+
throw err;
|
|
22
|
+
}
|
|
23
|
+
return (0, exports.callLambda)({
|
|
24
|
+
...options,
|
|
25
|
+
retriesRemaining: options.retriesRemaining - 1,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
exports.callLambda = callLambda;
|
|
30
|
+
const callLambdaWithoutRetry = async ({ functionName, type, payload, region, receivedStreamingPayload, timeoutInTest, }) => {
|
|
8
31
|
const res = await (0, aws_clients_1.getLambdaClient)(region, timeoutInTest).send(new client_lambda_1.InvokeWithResponseStreamCommand({
|
|
9
32
|
FunctionName: functionName,
|
|
10
33
|
Payload: JSON.stringify({ type, ...payload }),
|
|
@@ -38,13 +61,12 @@ const callLambda = async ({ functionName, type, payload, region, receivedStreami
|
|
|
38
61
|
const json = parseJson(responsePayload.trim());
|
|
39
62
|
return json;
|
|
40
63
|
};
|
|
41
|
-
exports.callLambda = callLambda;
|
|
42
64
|
const parseJsonWithErrorSurfacing = (input) => {
|
|
43
65
|
try {
|
|
44
66
|
return JSON.parse(input);
|
|
45
67
|
}
|
|
46
68
|
catch (_a) {
|
|
47
|
-
throw new Error(
|
|
69
|
+
throw new Error(`${INVALID_JSON_MESSAGE}. Response: ${input}`);
|
|
48
70
|
}
|
|
49
71
|
};
|
|
50
72
|
const parseJson = (input) => {
|
|
@@ -5,3 +5,8 @@ export declare const cleanupSerializedInputProps: ({ serialized, region, bucketN
|
|
|
5
5
|
region: AwsRegion;
|
|
6
6
|
bucketName: string;
|
|
7
7
|
}) => Promise<number>;
|
|
8
|
+
export declare const cleanupSerializedResolvedProps: ({ serialized, region, bucketName, }: {
|
|
9
|
+
serialized: SerializedInputProps;
|
|
10
|
+
region: AwsRegion;
|
|
11
|
+
bucketName: string;
|
|
12
|
+
}) => Promise<number>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.cleanupSerializedInputProps = void 0;
|
|
3
|
+
exports.cleanupSerializedResolvedProps = exports.cleanupSerializedInputProps = void 0;
|
|
4
4
|
const io_1 = require("../functions/helpers/io");
|
|
5
5
|
const constants_1 = require("./constants");
|
|
6
6
|
const cleanupSerializedInputProps = async ({ serialized, region, bucketName, }) => {
|
|
@@ -17,3 +17,17 @@ const cleanupSerializedInputProps = async ({ serialized, region, bucketName, })
|
|
|
17
17
|
return Date.now() - time;
|
|
18
18
|
};
|
|
19
19
|
exports.cleanupSerializedInputProps = cleanupSerializedInputProps;
|
|
20
|
+
const cleanupSerializedResolvedProps = async ({ serialized, region, bucketName, }) => {
|
|
21
|
+
if (serialized.type === 'payload') {
|
|
22
|
+
return 0;
|
|
23
|
+
}
|
|
24
|
+
const time = Date.now();
|
|
25
|
+
await (0, io_1.lambdaDeleteFile)({
|
|
26
|
+
bucketName,
|
|
27
|
+
key: (0, constants_1.resolvedPropsKey)(serialized.hash),
|
|
28
|
+
region,
|
|
29
|
+
customCredentials: null,
|
|
30
|
+
});
|
|
31
|
+
return Date.now() - time;
|
|
32
|
+
};
|
|
33
|
+
exports.cleanupSerializedResolvedProps = cleanupSerializedResolvedProps;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { AwsRegion } from '../client';
|
|
2
|
+
import type { SerializedInputProps } from './constants';
|
|
3
|
+
export declare const deserializeInputProps: ({ serialized, region, bucketName, expectedBucketOwner, }: {
|
|
4
|
+
serialized: SerializedInputProps;
|
|
5
|
+
region: AwsRegion;
|
|
6
|
+
bucketName: string;
|
|
7
|
+
expectedBucketOwner: string;
|
|
8
|
+
}) => Promise<Record<string, unknown>>;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.deserializeInputProps = void 0;
|
|
4
|
+
const io_1 = require("../functions/helpers/io");
|
|
5
|
+
const constants_1 = require("./constants");
|
|
6
|
+
const stream_to_string_1 = require("./stream-to-string");
|
|
7
|
+
const deserializeInputProps = async ({ serialized, region, bucketName, expectedBucketOwner, }) => {
|
|
8
|
+
if (serialized.type === 'payload') {
|
|
9
|
+
return JSON.parse(serialized.payload);
|
|
10
|
+
}
|
|
11
|
+
try {
|
|
12
|
+
const response = await (0, io_1.lambdaReadFile)({
|
|
13
|
+
bucketName,
|
|
14
|
+
expectedBucketOwner,
|
|
15
|
+
key: (0, constants_1.inputPropsKey)(serialized.hash),
|
|
16
|
+
region,
|
|
17
|
+
});
|
|
18
|
+
const body = await (0, stream_to_string_1.streamToString)(response);
|
|
19
|
+
const payload = JSON.parse(body);
|
|
20
|
+
return payload;
|
|
21
|
+
}
|
|
22
|
+
catch (err) {
|
|
23
|
+
throw new Error(`Failed to parse input props that were serialized: ${err.stack}`);
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
exports.deserializeInputProps = deserializeInputProps;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const isFlakyError: (err: Error) => boolean;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isFlakyError = void 0;
|
|
4
|
+
const isFlakyError = (err) => {
|
|
5
|
+
const { message } = err;
|
|
6
|
+
// storage.googleapis.com sometimes returns 500s, and Video does not have retry on its own
|
|
7
|
+
if ((message.includes('Format error') || message.includes('audio metadata')) &&
|
|
8
|
+
message.includes('storage.googleapis.com')) {
|
|
9
|
+
return true;
|
|
10
|
+
}
|
|
11
|
+
if (message.includes('FATAL:zygote_communication_linux.cc')) {
|
|
12
|
+
return true;
|
|
13
|
+
}
|
|
14
|
+
if (message.includes('error while loading shared libraries: libnss3.so')) {
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
if (message.includes('but the server sent no data')) {
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
if (message.includes('Compositor panicked')) {
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
if (message.includes('Compositor exited') && !message.includes('SIGSEGV')) {
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
if (message.includes('Timed out while setting up the headless browser')) {
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
return false;
|
|
30
|
+
};
|
|
31
|
+
exports.isFlakyError = isFlakyError;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { AwsRegion } from '../client';
|
|
2
|
+
import type { SerializedInputProps } from './constants';
|
|
3
|
+
export declare const serializeInputProps: ({ inputProps, region, type, userSpecifiedBucketName, }: {
|
|
4
|
+
inputProps: Record<string, unknown>;
|
|
5
|
+
region: AwsRegion;
|
|
6
|
+
type: 'still' | 'video-or-audio';
|
|
7
|
+
userSpecifiedBucketName: string | null;
|
|
8
|
+
}) => Promise<SerializedInputProps>;
|
|
9
|
+
export declare const deserializeInputProps: ({ serialized, region, bucketName, expectedBucketOwner, }: {
|
|
10
|
+
serialized: SerializedInputProps;
|
|
11
|
+
region: AwsRegion;
|
|
12
|
+
bucketName: string;
|
|
13
|
+
expectedBucketOwner: string;
|
|
14
|
+
}) => Promise<Record<string, unknown>>;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.deserializeInputProps = exports.serializeInputProps = void 0;
|
|
4
|
+
const get_or_create_bucket_1 = require("../api/get-or-create-bucket");
|
|
5
|
+
const io_1 = require("../functions/helpers/io");
|
|
6
|
+
const constants_1 = require("./constants");
|
|
7
|
+
const random_hash_1 = require("./random-hash");
|
|
8
|
+
const stream_to_string_1 = require("./stream-to-string");
|
|
9
|
+
const serializeInputProps = async ({ inputProps, region, type, userSpecifiedBucketName, }) => {
|
|
10
|
+
try {
|
|
11
|
+
const payload = JSON.stringify(inputProps);
|
|
12
|
+
const hash = (0, random_hash_1.randomHash)();
|
|
13
|
+
const MAX_INLINE_PAYLOAD_SIZE = type === 'still' ? 5000000 : 200000;
|
|
14
|
+
if (payload.length > MAX_INLINE_PAYLOAD_SIZE) {
|
|
15
|
+
console.warn(`Warning: inputProps are over ${Math.round(MAX_INLINE_PAYLOAD_SIZE / 1000)}KB (${Math.ceil(payload.length / 1024)}KB) in size. Uploading them to S3 to circumvent AWS Lambda payload size.`);
|
|
16
|
+
const bucketName = userSpecifiedBucketName !== null && userSpecifiedBucketName !== void 0 ? userSpecifiedBucketName : (await (0, get_or_create_bucket_1.getOrCreateBucket)({
|
|
17
|
+
region,
|
|
18
|
+
})).bucketName;
|
|
19
|
+
await (0, io_1.lambdaWriteFile)({
|
|
20
|
+
body: payload,
|
|
21
|
+
bucketName,
|
|
22
|
+
region,
|
|
23
|
+
customCredentials: null,
|
|
24
|
+
downloadBehavior: null,
|
|
25
|
+
expectedBucketOwner: null,
|
|
26
|
+
key: (0, constants_1.inputPropsKey)(hash),
|
|
27
|
+
privacy: 'public',
|
|
28
|
+
});
|
|
29
|
+
return {
|
|
30
|
+
type: 'bucket-url',
|
|
31
|
+
hash,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
type: 'payload',
|
|
36
|
+
payload,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
throw new Error('Error serializing inputProps. Check it has no circular references or reduce the size if the object is big.');
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
exports.serializeInputProps = serializeInputProps;
|
|
44
|
+
const deserializeInputProps = async ({ serialized, region, bucketName, expectedBucketOwner, }) => {
|
|
45
|
+
if (serialized.type === 'payload') {
|
|
46
|
+
return JSON.parse(serialized.payload);
|
|
47
|
+
}
|
|
48
|
+
try {
|
|
49
|
+
const response = await (0, io_1.lambdaReadFile)({
|
|
50
|
+
bucketName,
|
|
51
|
+
expectedBucketOwner,
|
|
52
|
+
key: (0, constants_1.inputPropsKey)(serialized.hash),
|
|
53
|
+
region,
|
|
54
|
+
});
|
|
55
|
+
const body = await (0, stream_to_string_1.streamToString)(response);
|
|
56
|
+
const payload = JSON.parse(body);
|
|
57
|
+
return payload;
|
|
58
|
+
}
|
|
59
|
+
catch (err) {
|
|
60
|
+
throw new Error(`Failed to parse input props that were serialized: ${err.stack}`);
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
exports.deserializeInputProps = deserializeInputProps;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remotion/lambda",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.18",
|
|
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.
|
|
30
|
-
"@remotion/cli": "4.0.
|
|
31
|
-
"
|
|
32
|
-
"remotion": "4.0.
|
|
29
|
+
"@remotion/bundler": "4.0.18",
|
|
30
|
+
"@remotion/cli": "4.0.18",
|
|
31
|
+
"remotion": "4.0.18",
|
|
32
|
+
"@remotion/renderer": "4.0.18"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"@jonny/eslint-config": "3.0.266",
|
|
@@ -41,14 +41,13 @@
|
|
|
41
41
|
"prettier": "^2.4.1",
|
|
42
42
|
"prettier-plugin-organize-imports": "^3.2.2",
|
|
43
43
|
"ts-node": "^10.8.0",
|
|
44
|
-
"typescript": "4.9.5",
|
|
45
44
|
"vitest": "0.31.1",
|
|
46
45
|
"zip-lib": "^0.7.2",
|
|
47
|
-
"@remotion/bundler": "4.0.
|
|
48
|
-
"@remotion/compositor-linux-arm64-gnu": "4.0.
|
|
46
|
+
"@remotion/bundler": "4.0.18",
|
|
47
|
+
"@remotion/compositor-linux-arm64-gnu": "4.0.18"
|
|
49
48
|
},
|
|
50
49
|
"peerDependencies": {
|
|
51
|
-
"@remotion/bundler": "4.0.
|
|
50
|
+
"@remotion/bundler": "4.0.18"
|
|
52
51
|
},
|
|
53
52
|
"publishConfig": {
|
|
54
53
|
"access": "public"
|
package/remotionlambda-arm64.zip
CHANGED
|
Binary file
|