@remotion/lambda 4.0.42 → 4.0.44

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.
@@ -4,6 +4,7 @@ exports.getProgress = void 0;
4
4
  const renderer_1 = require("@remotion/renderer");
5
5
  const remotion_1 = require("remotion");
6
6
  const constants_1 = require("../../shared/constants");
7
+ const parse_chunk_key_1 = require("../../shared/parse-chunk-key");
7
8
  const calculate_chunk_times_1 = require("./calculate-chunk-times");
8
9
  const calculate_price_from_bucket_1 = require("./calculate-price-from-bucket");
9
10
  const check_if_render_exists_1 = require("./check-if-render-exists");
@@ -167,16 +168,32 @@ const getProgress = async ({ bucketName, renderId, expectedBucketOwner, region,
167
168
  const chunkCount = outputFile
168
169
  ? (_g = renderMetadata === null || renderMetadata === void 0 ? void 0 : renderMetadata.totalChunks) !== null && _g !== void 0 ? _g : 0
169
170
  : chunks.length;
171
+ const availableChunks = chunks.map((c) => (0, parse_chunk_key_1.parseLambdaChunkKey)(c.Key));
172
+ const missingChunks = renderMetadata
173
+ ? new Array(renderMetadata.totalChunks)
174
+ .fill(true)
175
+ .map((_, i) => i)
176
+ .filter((index) => {
177
+ return !availableChunks.find((c) => c.chunk === index);
178
+ })
179
+ : null;
170
180
  // We add a 20 second buffer for it, since AWS timeshifts can be quite a lot. Once it's 20sec over the limit, we consider it timed out
171
- const isBeyondTimeout = renderMetadata &&
172
- Date.now() > renderMetadata.startedDate + timeoutInMilliseconds + 20000;
181
+ // 1. If we have missing chunks, we consider it timed out
182
+ const isBeyondTimeoutAndMissingChunks = renderMetadata &&
183
+ Date.now() > renderMetadata.startedDate + timeoutInMilliseconds + 20000 &&
184
+ missingChunks &&
185
+ missingChunks.length > 0;
186
+ // 2. If we have no missing chunks, but the encoding is not done, even after the additional `merge` function has been spawned, we consider it timed out
187
+ const isBeyondTimeoutAndHasStitchTimeout = renderMetadata &&
188
+ Date.now() > renderMetadata.startedDate + timeoutInMilliseconds * 2 + 20000;
173
189
  const allErrors = [
174
- isBeyondTimeout
190
+ isBeyondTimeoutAndMissingChunks || isBeyondTimeoutAndHasStitchTimeout
175
191
  ? (0, make_timeout_error_1.makeTimeoutError)({
176
192
  timeoutInMilliseconds,
177
193
  renderMetadata,
178
194
  chunks,
179
195
  renderId,
196
+ missingChunks: missingChunks !== null && missingChunks !== void 0 ? missingChunks : [],
180
197
  })
181
198
  : null,
182
199
  ...errorExplanations,
@@ -1,9 +1,10 @@
1
1
  import type { _Object } from '@aws-sdk/client-s3';
2
2
  import type { RenderMetadata } from '../../defaults';
3
3
  import type { EnhancedErrorInfo } from './write-lambda-error';
4
- export declare const makeTimeoutError: ({ timeoutInMilliseconds, chunks, renderMetadata, renderId, }: {
4
+ export declare const makeTimeoutError: ({ timeoutInMilliseconds, missingChunks, renderMetadata, renderId, }: {
5
5
  timeoutInMilliseconds: number;
6
6
  chunks: _Object[];
7
7
  renderMetadata: RenderMetadata;
8
8
  renderId: string;
9
+ missingChunks: number[];
9
10
  }) => EnhancedErrorInfo;
@@ -1,16 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.makeTimeoutError = void 0;
4
- const parse_chunk_key_1 = require("../../shared/parse-chunk-key");
5
4
  const make_timeout_message_1 = require("./make-timeout-message");
6
- const makeTimeoutError = ({ timeoutInMilliseconds, chunks, renderMetadata, renderId, }) => {
7
- const availableChunks = chunks.map((c) => (0, parse_chunk_key_1.parseLambdaChunkKey)(c.Key));
8
- const missingChunks = new Array(renderMetadata.totalChunks)
9
- .fill(true)
10
- .map((_, i) => i)
11
- .filter((index) => {
12
- return !availableChunks.find((c) => c.chunk === index);
13
- });
5
+ const makeTimeoutError = ({ timeoutInMilliseconds, missingChunks, renderMetadata, renderId, }) => {
14
6
  const message = (0, make_timeout_message_1.makeTimeoutMessage)({
15
7
  missingChunks,
16
8
  renderMetadata,
@@ -0,0 +1,30 @@
1
+ import type { AudioCodec } from '@remotion/renderer';
2
+ import type { CustomCredentials } from '../../shared/aws-clients';
3
+ import type { PostRenderData, Privacy, RenderMetadata, SerializedInputProps } from '../../shared/constants';
4
+ import type { DownloadBehavior } from '../../shared/content-disposition-header';
5
+ import type { LambdaCodec } from '../../shared/validate-lambda-codec';
6
+ export type OnAllChunksAvailable = (options: {
7
+ inputProps: SerializedInputProps;
8
+ serializedResolvedProps: SerializedInputProps;
9
+ }) => void;
10
+ export declare const mergeChunksAndFinishRender: (options: {
11
+ bucketName: string;
12
+ renderId: string;
13
+ expectedBucketOwner: string;
14
+ frameCountLength: number;
15
+ codec: LambdaCodec;
16
+ chunkCount: number;
17
+ fps: number;
18
+ numberOfGifLoops: number | null;
19
+ audioCodec: AudioCodec | null;
20
+ renderBucketName: string;
21
+ customCredentials: CustomCredentials | null;
22
+ downloadBehavior: DownloadBehavior;
23
+ key: string;
24
+ privacy: Privacy;
25
+ inputProps: SerializedInputProps;
26
+ verbose: boolean;
27
+ serializedResolvedProps: SerializedInputProps;
28
+ renderMetadata: RenderMetadata;
29
+ onAllChunks: OnAllChunksAvailable;
30
+ }) => Promise<PostRenderData>;
@@ -0,0 +1,199 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.mergeChunksAndFinishRender = void 0;
7
+ const renderer_1 = require("@remotion/renderer");
8
+ const fs_1 = __importDefault(require("fs"));
9
+ const node_fs_1 = require("node:fs");
10
+ const node_path_1 = require("node:path");
11
+ const cleanup_serialized_input_props_1 = require("../../shared/cleanup-serialized-input-props");
12
+ const constants_1 = require("../../shared/constants");
13
+ const concat_videos_1 = require("./concat-videos");
14
+ const create_post_render_data_1 = require("./create-post-render-data");
15
+ const delete_chunks_1 = require("./delete-chunks");
16
+ const get_current_region_1 = require("./get-current-region");
17
+ const get_files_to_delete_1 = require("./get-files-to-delete");
18
+ const get_output_url_from_metadata_1 = require("./get-output-url-from-metadata");
19
+ const inspect_errors_1 = require("./inspect-errors");
20
+ const io_1 = require("./io");
21
+ const write_lambda_error_1 = require("./write-lambda-error");
22
+ const write_post_render_data_1 = require("./write-post-render-data");
23
+ const mergeChunksAndFinishRender = async (options) => {
24
+ let lastProgressUploaded = 0;
25
+ const onProgress = (framesEncoded) => {
26
+ const relativeProgress = framesEncoded / options.frameCountLength;
27
+ const deltaSinceLastProgressUploaded = relativeProgress - lastProgressUploaded;
28
+ if (deltaSinceLastProgressUploaded < 0.1) {
29
+ return;
30
+ }
31
+ lastProgressUploaded = relativeProgress;
32
+ (0, io_1.lambdaWriteFile)({
33
+ bucketName: options.bucketName,
34
+ key: (0, constants_1.encodingProgressKey)(options.renderId),
35
+ body: String(Math.round(framesEncoded / constants_1.ENCODING_PROGRESS_STEP_SIZE)),
36
+ region: (0, get_current_region_1.getCurrentRegionInFunction)(),
37
+ privacy: 'private',
38
+ expectedBucketOwner: options.expectedBucketOwner,
39
+ downloadBehavior: null,
40
+ customCredentials: null,
41
+ }).catch((err) => {
42
+ (0, write_lambda_error_1.writeLambdaError)({
43
+ bucketName: options.bucketName,
44
+ errorInfo: {
45
+ chunk: null,
46
+ frame: null,
47
+ isFatal: false,
48
+ name: err.name,
49
+ message: err.message,
50
+ stack: `Could not upload stitching progress ${err.stack}`,
51
+ tmpDir: null,
52
+ type: 'stitcher',
53
+ attempt: 1,
54
+ totalAttempts: 1,
55
+ willRetry: false,
56
+ },
57
+ renderId: options.renderId,
58
+ expectedBucketOwner: options.expectedBucketOwner,
59
+ });
60
+ });
61
+ };
62
+ const onErrors = (errors) => {
63
+ renderer_1.RenderInternals.Log.error('Found Errors', errors);
64
+ const firstError = errors[0];
65
+ if (firstError.chunk !== null) {
66
+ throw new Error(`Stopping Lambda function because error occurred while rendering chunk ${firstError.chunk}:\n${errors[0].stack
67
+ .split('\n')
68
+ .map((s) => ` ${s}`)
69
+ .join('\n')}`);
70
+ }
71
+ throw new Error(`Stopping Lambda function because error occurred: ${errors[0].stack}`);
72
+ };
73
+ const outdir = (0, node_path_1.join)(renderer_1.RenderInternals.tmpDir(constants_1.CONCAT_FOLDER_TOKEN), 'bucket');
74
+ if ((0, node_fs_1.existsSync)(outdir)) {
75
+ (0, node_fs_1.rmSync)(outdir, {
76
+ recursive: true,
77
+ });
78
+ }
79
+ (0, node_fs_1.mkdirSync)(outdir);
80
+ const files = await (0, concat_videos_1.getAllFilesS3)({
81
+ bucket: options.bucketName,
82
+ expectedFiles: options.chunkCount,
83
+ outdir,
84
+ renderId: options.renderId,
85
+ region: (0, get_current_region_1.getCurrentRegionInFunction)(),
86
+ expectedBucketOwner: options.expectedBucketOwner,
87
+ onErrors,
88
+ });
89
+ options.onAllChunks({
90
+ inputProps: options.inputProps,
91
+ serializedResolvedProps: options.serializedResolvedProps,
92
+ });
93
+ const encodingStart = Date.now();
94
+ const { outfile, cleanupChunksProm } = await (0, concat_videos_1.concatVideosS3)({
95
+ onProgress,
96
+ numberOfFrames: options.frameCountLength,
97
+ codec: options.codec,
98
+ fps: options.fps,
99
+ numberOfGifLoops: options.numberOfGifLoops,
100
+ files,
101
+ outdir,
102
+ audioCodec: options.audioCodec,
103
+ });
104
+ const encodingStop = Date.now();
105
+ const outputSize = fs_1.default.statSync(outfile);
106
+ await (0, io_1.lambdaWriteFile)({
107
+ bucketName: options.renderBucketName,
108
+ key: options.key,
109
+ body: fs_1.default.createReadStream(outfile),
110
+ region: (0, get_current_region_1.getCurrentRegionInFunction)(),
111
+ privacy: options.privacy,
112
+ expectedBucketOwner: options.expectedBucketOwner,
113
+ downloadBehavior: options.downloadBehavior,
114
+ customCredentials: options.customCredentials,
115
+ });
116
+ const contents = await (0, io_1.lambdaLs)({
117
+ bucketName: options.bucketName,
118
+ prefix: (0, constants_1.rendersPrefix)(options.renderId),
119
+ expectedBucketOwner: options.expectedBucketOwner,
120
+ region: (0, get_current_region_1.getCurrentRegionInFunction)(),
121
+ });
122
+ const finalEncodingProgressProm = (0, io_1.lambdaWriteFile)({
123
+ bucketName: options.bucketName,
124
+ key: (0, constants_1.encodingProgressKey)(options.renderId),
125
+ body: String(Math.ceil(options.frameCountLength / constants_1.ENCODING_PROGRESS_STEP_SIZE)),
126
+ region: (0, get_current_region_1.getCurrentRegionInFunction)(),
127
+ privacy: 'private',
128
+ expectedBucketOwner: options.expectedBucketOwner,
129
+ downloadBehavior: null,
130
+ customCredentials: null,
131
+ });
132
+ const errorExplanationsProm = (0, inspect_errors_1.inspectErrors)({
133
+ contents,
134
+ renderId: options.renderId,
135
+ bucket: options.bucketName,
136
+ region: (0, get_current_region_1.getCurrentRegionInFunction)(),
137
+ expectedBucketOwner: options.expectedBucketOwner,
138
+ });
139
+ const jobs = (0, get_files_to_delete_1.getFilesToDelete)({
140
+ chunkCount: options.chunkCount,
141
+ renderId: options.renderId,
142
+ });
143
+ const deletProm = options.verbose
144
+ ? Promise.resolve(0)
145
+ : (0, delete_chunks_1.cleanupFiles)({
146
+ region: (0, get_current_region_1.getCurrentRegionInFunction)(),
147
+ bucket: options.bucketName,
148
+ contents,
149
+ jobs,
150
+ });
151
+ const cleanupSerializedInputPropsProm = (0, cleanup_serialized_input_props_1.cleanupSerializedInputProps)({
152
+ bucketName: options.bucketName,
153
+ region: (0, get_current_region_1.getCurrentRegionInFunction)(),
154
+ serialized: options.inputProps,
155
+ });
156
+ const cleanupResolvedInputPropsProm = (0, cleanup_serialized_input_props_1.cleanupSerializedResolvedProps)({
157
+ bucketName: options.bucketName,
158
+ region: (0, get_current_region_1.getCurrentRegionInFunction)(),
159
+ serialized: options.serializedResolvedProps,
160
+ });
161
+ const outputUrl = (0, get_output_url_from_metadata_1.getOutputUrlFromMetadata)(options.renderMetadata, options.bucketName, options.customCredentials);
162
+ const postRenderData = (0, create_post_render_data_1.createPostRenderData)({
163
+ expectedBucketOwner: options.expectedBucketOwner,
164
+ region: (0, get_current_region_1.getCurrentRegionInFunction)(),
165
+ renderId: options.renderId,
166
+ memorySizeInMb: Number(process.env.AWS_LAMBDA_FUNCTION_MEMORY_SIZE),
167
+ renderMetadata: options.renderMetadata,
168
+ contents,
169
+ errorExplanations: await errorExplanationsProm,
170
+ timeToEncode: encodingStop - encodingStart,
171
+ timeToDelete: (await Promise.all([
172
+ deletProm,
173
+ cleanupSerializedInputPropsProm,
174
+ cleanupResolvedInputPropsProm,
175
+ ])).reduce((a, b) => a + b, 0),
176
+ outputFile: {
177
+ lastModified: Date.now(),
178
+ size: outputSize.size,
179
+ url: outputUrl,
180
+ },
181
+ });
182
+ await finalEncodingProgressProm;
183
+ await (0, write_post_render_data_1.writePostRenderData)({
184
+ bucketName: options.bucketName,
185
+ expectedBucketOwner: options.expectedBucketOwner,
186
+ postRenderData,
187
+ region: (0, get_current_region_1.getCurrentRegionInFunction)(),
188
+ renderId: options.renderId,
189
+ });
190
+ await (0, io_1.lambdaDeleteFile)({
191
+ bucketName: options.bucketName,
192
+ key: (0, constants_1.initalizedMetadataKey)(options.renderId),
193
+ region: (0, get_current_region_1.getCurrentRegionInFunction)(),
194
+ customCredentials: null,
195
+ });
196
+ await Promise.all([cleanupChunksProm, fs_1.default.promises.rm(outfile)]);
197
+ return postRenderData;
198
+ };
199
+ exports.mergeChunksAndFinishRender = mergeChunksAndFinishRender;
@@ -12,6 +12,7 @@ const streamify_response_1 = require("./helpers/streamify-response");
12
12
  const streaming_payloads_1 = require("./helpers/streaming-payloads");
13
13
  const info_1 = require("./info");
14
14
  const launch_1 = require("./launch");
15
+ const merge_1 = require("./merge");
15
16
  const progress_1 = require("./progress");
16
17
  const renderer_2 = require("./renderer");
17
18
  const start_1 = require("./start");
@@ -123,6 +124,18 @@ const innerHandler = async (params, responseStream, context) => {
123
124
  });
124
125
  return;
125
126
  }
127
+ if (params.type === constants_1.LambdaRoutines.merge) {
128
+ (0, print_cloudwatch_helper_1.printCloudwatchHelper)(constants_1.LambdaRoutines.merge, {
129
+ renderId: params.renderId,
130
+ isWarm,
131
+ });
132
+ const response = await (0, merge_1.mergeHandler)(params, {
133
+ expectedBucketOwner: currentUserId,
134
+ });
135
+ responseStream.write(JSON.stringify(response), () => {
136
+ responseStream.end();
137
+ });
138
+ }
126
139
  if (params.type === constants_1.LambdaRoutines.compositions) {
127
140
  (0, print_cloudwatch_helper_1.printCloudwatchHelper)(constants_1.LambdaRoutines.compositions, {
128
141
  isWarm,
@@ -1,39 +1,14 @@
1
1
  "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
25
2
  Object.defineProperty(exports, "__esModule", { value: true });
26
3
  exports.launchHandler = void 0;
27
4
  const client_lambda_1 = require("@aws-sdk/client-lambda");
28
5
  const renderer_1 = require("@remotion/renderer");
29
- const node_fs_1 = __importStar(require("node:fs"));
30
- const node_path_1 = require("node:path");
31
6
  const version_1 = require("remotion/version");
32
7
  const aws_clients_1 = require("../shared/aws-clients");
33
- const cleanup_serialized_input_props_1 = require("../shared/cleanup-serialized-input-props");
34
8
  const compress_props_1 = require("../shared/compress-props");
35
9
  const constants_1 = require("../shared/constants");
36
10
  const docs_url_1 = require("../shared/docs-url");
11
+ const get_aws_urls_1 = require("../shared/get-aws-urls");
37
12
  const invoke_webhook_1 = require("../shared/invoke-webhook");
38
13
  const validate_1 = require("../shared/validate");
39
14
  const validate_frames_per_lambda_1 = require("../shared/validate-frames-per-lambda");
@@ -41,21 +16,15 @@ const validate_outname_1 = require("../shared/validate-outname");
41
16
  const validate_privacy_1 = require("../shared/validate-privacy");
42
17
  const plan_frame_ranges_1 = require("./chunk-optimization/plan-frame-ranges");
43
18
  const best_frames_per_lambda_param_1 = require("./helpers/best-frames-per-lambda-param");
44
- const concat_videos_1 = require("./helpers/concat-videos");
45
- const create_post_render_data_1 = require("./helpers/create-post-render-data");
46
- const delete_chunks_1 = require("./helpers/delete-chunks");
47
19
  const expected_out_name_1 = require("./helpers/expected-out-name");
48
20
  const find_output_file_in_bucket_1 = require("./helpers/find-output-file-in-bucket");
49
21
  const get_browser_instance_1 = require("./helpers/get-browser-instance");
50
22
  const get_current_region_1 = require("./helpers/get-current-region");
51
- const get_files_to_delete_1 = require("./helpers/get-files-to-delete");
52
- const get_output_url_from_metadata_1 = require("./helpers/get-output-url-from-metadata");
53
- const inspect_errors_1 = require("./helpers/inspect-errors");
54
23
  const io_1 = require("./helpers/io");
24
+ const merge_chunks_1 = require("./helpers/merge-chunks");
55
25
  const timer_1 = require("./helpers/timer");
56
26
  const validate_composition_1 = require("./helpers/validate-composition");
57
27
  const write_lambda_error_1 = require("./helpers/write-lambda-error");
58
- const write_post_render_data_1 = require("./helpers/write-post-render-data");
59
28
  const callFunctionWithRetry = async ({ payload, retries, functionName, }) => {
60
29
  try {
61
30
  await (0, aws_clients_1.getLambdaClient)((0, get_current_region_1.getCurrentRegionInFunction)()).send(new client_lambda_1.InvokeCommand({
@@ -81,14 +50,12 @@ const callFunctionWithRetry = async ({ payload, retries, functionName, }) => {
81
50
  throw err;
82
51
  }
83
52
  };
84
- const innerLaunchHandler = async (params, options) => {
85
- var _a, _b, _c, _d, _e, _f;
53
+ const innerLaunchHandler = async ({ functionName, params, options, onAllChunksAvailable, verbose, }) => {
54
+ var _a, _b, _c, _d, _e;
86
55
  if (params.type !== constants_1.LambdaRoutines.launch) {
87
56
  throw new Error('Expected launch type');
88
57
  }
89
- const functionName = (_a = params.rendererFunctionName) !== null && _a !== void 0 ? _a : process.env.AWS_LAMBDA_FUNCTION_NAME;
90
58
  const startedDate = Date.now();
91
- const verbose = renderer_1.RenderInternals.isEqualOrBelowLogLevel(params.logLevel, 'verbose');
92
59
  const browserInstance = await (0, get_browser_instance_1.getBrowserInstance)(params.logLevel, false, params.chromiumOptions);
93
60
  const inputPropsPromise = (0, compress_props_1.decompressInputProps)({
94
61
  bucketName: params.bucketName,
@@ -104,7 +71,7 @@ const innerLaunchHandler = async (params, options) => {
104
71
  composition: params.composition,
105
72
  browserInstance,
106
73
  serializedInputPropsWithCustomSchema,
107
- envVariables: (_b = params.envVariables) !== null && _b !== void 0 ? _b : {},
74
+ envVariables: (_a = params.envVariables) !== null && _a !== void 0 ? _a : {},
108
75
  timeoutInMilliseconds: params.timeoutInMilliseconds,
109
76
  chromiumOptions: params.chromiumOptions,
110
77
  port: null,
@@ -131,15 +98,11 @@ const innerLaunchHandler = async (params, options) => {
131
98
  });
132
99
  const realFrameRange = renderer_1.RenderInternals.getRealFrameRange(comp.durationInFrames, params.frameRange);
133
100
  const frameCount = renderer_1.RenderInternals.getFramesToRender(realFrameRange, params.everyNthFrame);
134
- const framesPerLambda = (_c = params.framesPerLambda) !== null && _c !== void 0 ? _c : (0, best_frames_per_lambda_param_1.bestFramesPerLambdaParam)(frameCount.length);
101
+ const framesPerLambda = (_b = params.framesPerLambda) !== null && _b !== void 0 ? _b : (0, best_frames_per_lambda_param_1.bestFramesPerLambdaParam)(frameCount.length);
135
102
  (0, validate_frames_per_lambda_1.validateFramesPerLambda)({
136
103
  framesPerLambda,
137
104
  durationInFrames: frameCount.length,
138
105
  });
139
- const chunkCount = Math.ceil(frameCount.length / framesPerLambda);
140
- if (chunkCount > constants_1.MAX_FUNCTIONS_PER_RENDER) {
141
- throw new Error(`Too many functions: This render would cause ${chunkCount} functions to spawn. We limit this amount to ${constants_1.MAX_FUNCTIONS_PER_RENDER} functions as more would result in diminishing returns. Values set: frameCount = ${frameCount}, framesPerLambda=${framesPerLambda}. See ${docs_url_1.DOCS_URL}/docs/lambda/concurrency#too-many-functions for help.`);
142
- }
143
106
  (0, validate_outname_1.validateOutname)(params.outName, params.codec, params.audioCodec);
144
107
  (0, validate_privacy_1.validatePrivacy)(params.privacy, true);
145
108
  renderer_1.RenderInternals.validatePuppeteerTimeout(params.timeoutInMilliseconds);
@@ -148,6 +111,9 @@ const innerLaunchHandler = async (params, options) => {
148
111
  frameRange: realFrameRange,
149
112
  everyNthFrame: params.everyNthFrame,
150
113
  });
114
+ if (chunks.length > constants_1.MAX_FUNCTIONS_PER_RENDER) {
115
+ throw new Error(`Too many functions: This render would cause ${chunks.length} functions to spawn. We limit this amount to ${constants_1.MAX_FUNCTIONS_PER_RENDER} functions as more would result in diminishing returns. Values set: frameCount = ${frameCount}, framesPerLambda=${framesPerLambda}. See ${docs_url_1.DOCS_URL}/docs/lambda/concurrency#too-many-functions for help.`);
116
+ }
151
117
  const sortedChunks = chunks.slice().sort((a, b) => a[0] - b[0]);
152
118
  const reqSend = (0, timer_1.timer)('sending off requests');
153
119
  const serializedResolved = (0, compress_props_1.serializeOrThrow)(comp.props, 'resolved-props');
@@ -232,16 +198,18 @@ const innerLaunchHandler = async (params, options) => {
232
198
  memorySizeInMb: Number(process.env.AWS_LAMBDA_FUNCTION_MEMORY_SIZE),
233
199
  region: (0, get_current_region_1.getCurrentRegionInFunction)(),
234
200
  renderId: params.renderId,
235
- outName: (_d = params.outName) !== null && _d !== void 0 ? _d : undefined,
201
+ outName: (_c = params.outName) !== null && _c !== void 0 ? _c : undefined,
236
202
  privacy: params.privacy,
237
203
  everyNthFrame: params.everyNthFrame,
238
204
  frameRange: realFrameRange,
239
205
  audioCodec: params.audioCodec,
240
206
  deleteAfter: params.deleteAfter,
207
+ numberOfGifLoops: params.numberOfGifLoops,
208
+ downloadBehavior: params.downloadBehavior,
241
209
  };
242
210
  const { key, renderBucketName, customCredentials } = (0, expected_out_name_1.getExpectedOutName)(renderMetadata, params.bucketName, typeof params.outName === 'string' || typeof params.outName === 'undefined'
243
211
  ? null
244
- : (_f = (_e = params.outName) === null || _e === void 0 ? void 0 : _e.s3OutputProvider) !== null && _f !== void 0 ? _f : null);
212
+ : (_e = (_d = params.outName) === null || _d === void 0 ? void 0 : _d.s3OutputProvider) !== null && _e !== void 0 ? _e : null);
245
213
  const output = await (0, find_output_file_in_bucket_1.findOutputFileInBucket)({
246
214
  bucketName: params.bucketName,
247
215
  customCredentials,
@@ -276,209 +244,77 @@ const innerLaunchHandler = async (params, options) => {
276
244
  await callFunctionWithRetry({ payload, retries: 0, functionName });
277
245
  }));
278
246
  reqSend.end();
279
- let lastProgressUploaded = 0;
280
- const onProgress = (framesEncoded) => {
281
- const relativeProgress = framesEncoded / frameCount.length;
282
- const deltaSinceLastProgressUploaded = relativeProgress - lastProgressUploaded;
283
- if (deltaSinceLastProgressUploaded < 0.1) {
284
- return;
285
- }
286
- lastProgressUploaded = relativeProgress;
287
- (0, io_1.lambdaWriteFile)({
288
- bucketName: params.bucketName,
289
- key: (0, constants_1.encodingProgressKey)(params.renderId),
290
- body: String(Math.round(framesEncoded / constants_1.ENCODING_PROGRESS_STEP_SIZE)),
291
- region: (0, get_current_region_1.getCurrentRegionInFunction)(),
292
- privacy: 'private',
293
- expectedBucketOwner: options.expectedBucketOwner,
294
- downloadBehavior: null,
295
- customCredentials: null,
296
- }).catch((err) => {
297
- (0, write_lambda_error_1.writeLambdaError)({
298
- bucketName: params.bucketName,
299
- errorInfo: {
300
- chunk: null,
301
- frame: null,
302
- isFatal: false,
303
- name: err.name,
304
- message: err.message,
305
- stack: `Could not upload stitching progress ${err.stack}`,
306
- tmpDir: null,
307
- type: 'stitcher',
308
- attempt: 1,
309
- totalAttempts: 1,
310
- willRetry: false,
311
- },
312
- renderId: params.renderId,
313
- expectedBucketOwner: options.expectedBucketOwner,
314
- });
315
- });
316
- };
317
- const onErrors = (errors) => {
318
- renderer_1.RenderInternals.Log.error('Found Errors', errors);
319
- const firstError = errors[0];
320
- if (firstError.chunk !== null) {
321
- throw new Error(`Stopping Lambda function because error occurred while rendering chunk ${firstError.chunk}:\n${errors[0].stack
322
- .split('\n')
323
- .map((s) => ` ${s}`)
324
- .join('\n')}`);
325
- }
326
- throw new Error(`Stopping Lambda function because error occurred: ${errors[0].stack}`);
327
- };
328
247
  const fps = comp.fps / params.everyNthFrame;
329
- const outdir = (0, node_path_1.join)(renderer_1.RenderInternals.tmpDir(constants_1.CONCAT_FOLDER_TOKEN), 'bucket');
330
- if ((0, node_fs_1.existsSync)(outdir)) {
331
- (0, node_fs_1.rmSync)(outdir, {
332
- recursive: true,
333
- });
334
- }
335
- (0, node_fs_1.mkdirSync)(outdir);
336
- const files = await (0, concat_videos_1.getAllFilesS3)({
337
- bucket: params.bucketName,
338
- expectedFiles: chunkCount,
339
- outdir,
248
+ const postRenderData = await (0, merge_chunks_1.mergeChunksAndFinishRender)({
249
+ bucketName: params.bucketName,
340
250
  renderId: params.renderId,
341
- region: (0, get_current_region_1.getCurrentRegionInFunction)(),
342
251
  expectedBucketOwner: options.expectedBucketOwner,
343
- onErrors,
344
- });
345
- const encodingStart = Date.now();
346
- const { outfile, cleanupChunksProm } = await (0, concat_videos_1.concatVideosS3)({
347
- onProgress,
348
- numberOfFrames: frameCount.length,
252
+ frameCountLength: frameCount.length,
253
+ audioCodec: params.audioCodec,
254
+ chunkCount: chunks.length,
349
255
  codec: params.codec,
256
+ customCredentials,
257
+ downloadBehavior: params.downloadBehavior,
350
258
  fps,
351
- numberOfGifLoops: params.numberOfGifLoops,
352
- files,
353
- outdir,
354
- audioCodec: params.audioCodec,
355
- });
356
- const encodingStop = Date.now();
357
- const outputSize = node_fs_1.default.statSync(outfile);
358
- await (0, io_1.lambdaWriteFile)({
359
- bucketName: renderBucketName,
360
259
  key,
361
- body: node_fs_1.default.createReadStream(outfile),
362
- region: (0, get_current_region_1.getCurrentRegionInFunction)(),
260
+ numberOfGifLoops: params.numberOfGifLoops,
363
261
  privacy: params.privacy,
364
- expectedBucketOwner: options.expectedBucketOwner,
365
- downloadBehavior: params.downloadBehavior,
366
- customCredentials,
367
- });
368
- const contents = await (0, io_1.lambdaLs)({
369
- bucketName: params.bucketName,
370
- prefix: (0, constants_1.rendersPrefix)(params.renderId),
371
- expectedBucketOwner: options.expectedBucketOwner,
372
- region: (0, get_current_region_1.getCurrentRegionInFunction)(),
373
- });
374
- const finalEncodingProgressProm = (0, io_1.lambdaWriteFile)({
375
- bucketName: params.bucketName,
376
- key: (0, constants_1.encodingProgressKey)(params.renderId),
377
- body: String(Math.ceil(frameCount.length / constants_1.ENCODING_PROGRESS_STEP_SIZE)),
378
- region: (0, get_current_region_1.getCurrentRegionInFunction)(),
379
- privacy: 'private',
380
- expectedBucketOwner: options.expectedBucketOwner,
381
- downloadBehavior: null,
382
- customCredentials: null,
383
- });
384
- const errorExplanationsProm = (0, inspect_errors_1.inspectErrors)({
385
- contents,
386
- renderId: params.renderId,
387
- bucket: params.bucketName,
388
- region: (0, get_current_region_1.getCurrentRegionInFunction)(),
389
- expectedBucketOwner: options.expectedBucketOwner,
390
- });
391
- const jobs = (0, get_files_to_delete_1.getFilesToDelete)({
392
- chunkCount,
393
- renderId: params.renderId,
394
- });
395
- const deletProm = verbose
396
- ? Promise.resolve(0)
397
- : (0, delete_chunks_1.cleanupFiles)({
398
- region: (0, get_current_region_1.getCurrentRegionInFunction)(),
399
- bucket: params.bucketName,
400
- contents,
401
- jobs,
402
- });
403
- const cleanupSerializedInputPropsProm = (0, cleanup_serialized_input_props_1.cleanupSerializedInputProps)({
404
- bucketName: params.bucketName,
405
- region: (0, get_current_region_1.getCurrentRegionInFunction)(),
406
- serialized: params.inputProps,
407
- });
408
- const cleanupResolvedInputPropsProm = (0, cleanup_serialized_input_props_1.cleanupSerializedResolvedProps)({
409
- bucketName: params.bucketName,
410
- region: (0, get_current_region_1.getCurrentRegionInFunction)(),
411
- serialized: serializedResolvedProps,
412
- });
413
- const outputUrl = (0, get_output_url_from_metadata_1.getOutputUrlFromMetadata)(renderMetadata, params.bucketName, customCredentials);
414
- const postRenderData = (0, create_post_render_data_1.createPostRenderData)({
415
- expectedBucketOwner: options.expectedBucketOwner,
416
- region: (0, get_current_region_1.getCurrentRegionInFunction)(),
417
- renderId: params.renderId,
418
- memorySizeInMb: Number(process.env.AWS_LAMBDA_FUNCTION_MEMORY_SIZE),
262
+ renderBucketName,
263
+ inputProps: params.inputProps,
264
+ serializedResolvedProps,
265
+ verbose,
419
266
  renderMetadata,
420
- contents,
421
- errorExplanations: await errorExplanationsProm,
422
- timeToEncode: encodingStop - encodingStart,
423
- timeToDelete: (await Promise.all([
424
- deletProm,
425
- cleanupSerializedInputPropsProm,
426
- cleanupResolvedInputPropsProm,
427
- ])).reduce((a, b) => a + b, 0),
428
- outputFile: {
429
- lastModified: Date.now(),
430
- size: outputSize.size,
431
- url: outputUrl,
432
- },
267
+ onAllChunks: onAllChunksAvailable,
433
268
  });
434
- await finalEncodingProgressProm;
435
- await (0, write_post_render_data_1.writePostRenderData)({
436
- bucketName: params.bucketName,
437
- expectedBucketOwner: options.expectedBucketOwner,
438
- postRenderData,
439
- region: (0, get_current_region_1.getCurrentRegionInFunction)(),
440
- renderId: params.renderId,
441
- });
442
- await (0, io_1.lambdaDeleteFile)({
443
- bucketName: params.bucketName,
444
- key: (0, constants_1.initalizedMetadataKey)(params.renderId),
445
- region: (0, get_current_region_1.getCurrentRegionInFunction)(),
446
- customCredentials: null,
447
- });
448
- await Promise.all([cleanupChunksProm, node_fs_1.default.promises.rm(outfile)]);
449
269
  return postRenderData;
450
270
  };
451
271
  const launchHandler = async (params, options) => {
452
- var _a, _b;
272
+ var _a, _b, _c;
453
273
  if (params.type !== constants_1.LambdaRoutines.launch) {
454
274
  throw new Error('Expected launch type');
455
275
  }
456
- let webhookInvoked = false;
457
- const webhookDueToTimeout = setTimeout(async () => {
276
+ let allChunksAvailable = null;
277
+ const functionName = (_a = params.rendererFunctionName) !== null && _a !== void 0 ? _a : process.env.AWS_LAMBDA_FUNCTION_NAME;
278
+ const verbose = renderer_1.RenderInternals.isEqualOrBelowLogLevel(params.logLevel, 'verbose');
279
+ const onTimeout = async () => {
458
280
  var _a;
459
- if (params.webhook && !webhookInvoked) {
281
+ if (allChunksAvailable) {
282
+ renderer_1.RenderInternals.Log.info('All chunks are available, but the function is about to time out.');
283
+ renderer_1.RenderInternals.Log.info('Spawning another function to merge chunks.');
460
284
  try {
461
- await (0, invoke_webhook_1.invokeWebhook)({
462
- url: params.webhook.url,
463
- secret: params.webhook.secret,
285
+ await callFunctionWithRetry({
286
+ functionName,
464
287
  payload: {
465
- type: 'timeout',
288
+ type: constants_1.LambdaRoutines.merge,
466
289
  renderId: params.renderId,
467
- expectedBucketOwner: options.expectedBucketOwner,
468
290
  bucketName: params.bucketName,
469
- customData: (_a = params.webhook.customData) !== null && _a !== void 0 ? _a : null,
291
+ verbose,
292
+ outName: params.outName,
293
+ serializedResolvedProps: allChunksAvailable.serializedResolvedProps,
294
+ inputProps: allChunksAvailable.inputProps,
470
295
  },
296
+ retries: 2,
471
297
  });
472
- webhookInvoked = true;
298
+ renderer_1.RenderInternals.Log.info(`New function successfully invoked. See the CloudWatch logs for it:`);
299
+ renderer_1.RenderInternals.Log.info((0, get_aws_urls_1.getCloudwatchMethodUrl)({
300
+ functionName: process.env.AWS_LAMBDA_FUNCTION_NAME,
301
+ method: constants_1.LambdaRoutines.merge,
302
+ region: (0, get_current_region_1.getCurrentRegionInFunction)(),
303
+ rendererFunctionName: params.rendererFunctionName,
304
+ renderId: params.renderId,
305
+ }));
306
+ renderer_1.RenderInternals.Log.info('This function will now time out.');
473
307
  }
474
308
  catch (err) {
475
309
  if (process.env.NODE_ENV === 'test') {
476
310
  throw err;
477
311
  }
312
+ renderer_1.RenderInternals.Log.error('Failed to invoke additional function to merge videos:');
313
+ renderer_1.RenderInternals.Log.error(err);
478
314
  await (0, write_lambda_error_1.writeLambdaError)({
479
315
  bucketName: params.bucketName,
480
316
  errorInfo: {
481
- type: 'webhook',
317
+ type: 'stitcher',
482
318
  message: err.message,
483
319
  name: err.name,
484
320
  stack: err.stack,
@@ -493,60 +329,116 @@ const launchHandler = async (params, options) => {
493
329
  renderId: params.renderId,
494
330
  expectedBucketOwner: options.expectedBucketOwner,
495
331
  });
496
- renderer_1.RenderInternals.Log.error('Failed to invoke webhook:');
497
- renderer_1.RenderInternals.Log.error(err);
498
332
  }
499
333
  }
500
- }, Math.max(options.getRemainingTimeInMillis() - 1000, 1000));
334
+ if (!params.webhook) {
335
+ return;
336
+ }
337
+ if (webhookInvoked) {
338
+ return;
339
+ }
340
+ try {
341
+ await (0, invoke_webhook_1.invokeWebhook)({
342
+ url: params.webhook.url,
343
+ secret: params.webhook.secret,
344
+ payload: {
345
+ type: 'timeout',
346
+ renderId: params.renderId,
347
+ expectedBucketOwner: options.expectedBucketOwner,
348
+ bucketName: params.bucketName,
349
+ customData: (_a = params.webhook.customData) !== null && _a !== void 0 ? _a : null,
350
+ },
351
+ });
352
+ webhookInvoked = true;
353
+ }
354
+ catch (err) {
355
+ if (process.env.NODE_ENV === 'test') {
356
+ throw err;
357
+ }
358
+ renderer_1.RenderInternals.Log.error('Failed to invoke webhook:');
359
+ renderer_1.RenderInternals.Log.error(err);
360
+ await (0, write_lambda_error_1.writeLambdaError)({
361
+ bucketName: params.bucketName,
362
+ errorInfo: {
363
+ type: 'webhook',
364
+ message: err.message,
365
+ name: err.name,
366
+ stack: err.stack,
367
+ tmpDir: null,
368
+ frame: 0,
369
+ chunk: 0,
370
+ isFatal: false,
371
+ attempt: 1,
372
+ willRetry: false,
373
+ totalAttempts: 1,
374
+ },
375
+ renderId: params.renderId,
376
+ expectedBucketOwner: options.expectedBucketOwner,
377
+ });
378
+ }
379
+ };
380
+ let webhookInvoked = false;
381
+ const webhookDueToTimeout = setTimeout(onTimeout, Math.max(options.getRemainingTimeInMillis() - 1000, 1000));
501
382
  renderer_1.RenderInternals.Log.info(`Function has ${Math.max(options.getRemainingTimeInMillis() - 1000, 1000)} before it times out`);
502
383
  try {
503
- const postRenderData = await innerLaunchHandler(params, options);
384
+ const postRenderData = await innerLaunchHandler({
385
+ functionName,
386
+ params,
387
+ options,
388
+ onAllChunksAvailable: ({ inputProps, serializedResolvedProps }) => {
389
+ allChunksAvailable = { inputProps, serializedResolvedProps };
390
+ },
391
+ verbose,
392
+ });
504
393
  clearTimeout(webhookDueToTimeout);
505
- if (params.webhook && !webhookInvoked) {
506
- try {
507
- await (0, invoke_webhook_1.invokeWebhook)({
508
- url: params.webhook.url,
509
- secret: params.webhook.secret,
510
- payload: {
511
- type: 'success',
512
- renderId: params.renderId,
513
- expectedBucketOwner: options.expectedBucketOwner,
514
- bucketName: params.bucketName,
515
- customData: (_a = params.webhook.customData) !== null && _a !== void 0 ? _a : null,
516
- outputUrl: postRenderData.outputFile,
517
- lambdaErrors: postRenderData.errors,
518
- outputFile: postRenderData.outputFile,
519
- timeToFinish: postRenderData.timeToFinish,
520
- costs: postRenderData.cost,
521
- },
522
- });
523
- webhookInvoked = true;
524
- }
525
- catch (err) {
526
- if (process.env.NODE_ENV === 'test') {
527
- throw err;
528
- }
529
- await (0, write_lambda_error_1.writeLambdaError)({
530
- bucketName: params.bucketName,
531
- errorInfo: {
532
- type: 'webhook',
533
- message: err.message,
534
- name: err.name,
535
- stack: err.stack,
536
- tmpDir: null,
537
- frame: 0,
538
- chunk: 0,
539
- isFatal: false,
540
- attempt: 1,
541
- willRetry: false,
542
- totalAttempts: 1,
543
- },
394
+ if (!params.webhook || webhookInvoked) {
395
+ return {
396
+ type: 'success',
397
+ };
398
+ }
399
+ try {
400
+ await (0, invoke_webhook_1.invokeWebhook)({
401
+ url: params.webhook.url,
402
+ secret: params.webhook.secret,
403
+ payload: {
404
+ type: 'success',
544
405
  renderId: params.renderId,
545
406
  expectedBucketOwner: options.expectedBucketOwner,
546
- });
547
- renderer_1.RenderInternals.Log.error('Failed to invoke webhook:');
548
- renderer_1.RenderInternals.Log.error(err);
407
+ bucketName: params.bucketName,
408
+ customData: (_b = params.webhook.customData) !== null && _b !== void 0 ? _b : null,
409
+ outputUrl: postRenderData.outputFile,
410
+ lambdaErrors: postRenderData.errors,
411
+ outputFile: postRenderData.outputFile,
412
+ timeToFinish: postRenderData.timeToFinish,
413
+ costs: postRenderData.cost,
414
+ },
415
+ });
416
+ webhookInvoked = true;
417
+ }
418
+ catch (err) {
419
+ if (process.env.NODE_ENV === 'test') {
420
+ throw err;
549
421
  }
422
+ await (0, write_lambda_error_1.writeLambdaError)({
423
+ bucketName: params.bucketName,
424
+ errorInfo: {
425
+ type: 'webhook',
426
+ message: err.message,
427
+ name: err.name,
428
+ stack: err.stack,
429
+ tmpDir: null,
430
+ frame: 0,
431
+ chunk: 0,
432
+ isFatal: false,
433
+ attempt: 1,
434
+ willRetry: false,
435
+ totalAttempts: 1,
436
+ },
437
+ renderId: params.renderId,
438
+ expectedBucketOwner: options.expectedBucketOwner,
439
+ });
440
+ renderer_1.RenderInternals.Log.error('Failed to invoke webhook:');
441
+ renderer_1.RenderInternals.Log.error(err);
550
442
  }
551
443
  return {
552
444
  type: 'success',
@@ -586,7 +478,7 @@ const launchHandler = async (params, options) => {
586
478
  renderId: params.renderId,
587
479
  expectedBucketOwner: options.expectedBucketOwner,
588
480
  bucketName: params.bucketName,
589
- customData: (_b = params.webhook.customData) !== null && _b !== void 0 ? _b : null,
481
+ customData: (_c = params.webhook.customData) !== null && _c !== void 0 ? _c : null,
590
482
  errors: [err].map((e) => ({
591
483
  message: e.message,
592
484
  name: e.name,
@@ -0,0 +1,9 @@
1
+ import type { LambdaPayload, PostRenderData } from '../defaults';
2
+ type Options = {
3
+ expectedBucketOwner: string;
4
+ };
5
+ export declare const mergeHandler: (params: LambdaPayload, options: Options) => Promise<{
6
+ type: 'success';
7
+ postRenderData: PostRenderData;
8
+ }>;
9
+ export {};
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.mergeHandler = void 0;
4
+ const renderer_1 = require("@remotion/renderer");
5
+ const defaults_1 = require("../defaults");
6
+ const expected_out_name_1 = require("./helpers/expected-out-name");
7
+ const get_current_region_1 = require("./helpers/get-current-region");
8
+ const get_render_metadata_1 = require("./helpers/get-render-metadata");
9
+ const merge_chunks_1 = require("./helpers/merge-chunks");
10
+ const mergeHandler = async (params, options) => {
11
+ var _a, _b;
12
+ if (params.type !== defaults_1.LambdaRoutines.merge) {
13
+ throw new Error('Expected launch type');
14
+ }
15
+ renderer_1.RenderInternals.Log.info('This function has been started because the previous main function has timed out while merging together the chunks.');
16
+ renderer_1.RenderInternals.Log.info('The merging of chunks will now restart.');
17
+ const renderMetadata = await (0, get_render_metadata_1.getRenderMetadata)({
18
+ bucketName: params.bucketName,
19
+ expectedBucketOwner: options.expectedBucketOwner,
20
+ region: (0, get_current_region_1.getCurrentRegionInFunction)(),
21
+ renderId: params.renderId,
22
+ });
23
+ if (!renderMetadata.codec) {
24
+ throw new Error('expected codec');
25
+ }
26
+ const { key, renderBucketName, customCredentials } = (0, expected_out_name_1.getExpectedOutName)(renderMetadata, params.bucketName, typeof params.outName === 'string' || typeof params.outName === 'undefined'
27
+ ? null
28
+ : (_b = (_a = params.outName) === null || _a === void 0 ? void 0 : _a.s3OutputProvider) !== null && _b !== void 0 ? _b : null);
29
+ const frameCount = renderer_1.RenderInternals.getFramesToRender(renderMetadata.frameRange, renderMetadata.everyNthFrame);
30
+ const fps = renderMetadata.videoConfig.fps / renderMetadata.everyNthFrame;
31
+ const postRenderData = await (0, merge_chunks_1.mergeChunksAndFinishRender)({
32
+ audioCodec: renderMetadata.audioCodec,
33
+ bucketName: params.bucketName,
34
+ chunkCount: renderMetadata.totalChunks,
35
+ codec: renderMetadata.codec,
36
+ customCredentials,
37
+ downloadBehavior: renderMetadata.downloadBehavior,
38
+ expectedBucketOwner: options.expectedBucketOwner,
39
+ fps,
40
+ frameCountLength: frameCount.length,
41
+ inputProps: params.inputProps,
42
+ key,
43
+ numberOfGifLoops: renderMetadata.numberOfGifLoops,
44
+ privacy: renderMetadata.privacy,
45
+ renderBucketName,
46
+ renderId: params.renderId,
47
+ renderMetadata,
48
+ serializedResolvedProps: params.serializedResolvedProps,
49
+ verbose: params.verbose,
50
+ onAllChunks: () => {
51
+ renderer_1.RenderInternals.Log.info('All chunks have been downloaded now.');
52
+ },
53
+ });
54
+ return { type: 'success', postRenderData };
55
+ };
56
+ exports.mergeHandler = mergeHandler;
@@ -115,6 +115,8 @@ const innerStillHandler = async ({ params: lambdaParams, expectedBucketOwner, re
115
115
  frameRange: [lambdaParams.frame, lambdaParams.frame],
116
116
  audioCodec: null,
117
117
  deleteAfter: lambdaParams.deleteAfter,
118
+ numberOfGifLoops: null,
119
+ downloadBehavior: lambdaParams.downloadBehavior,
118
120
  };
119
121
  await (0, io_1.lambdaWriteFile)({
120
122
  bucketName,
@@ -1,4 +1,4 @@
1
- import type { AudioCodec, ChromiumOptions, Codec, ColorSpace, FrameRange, LogLevel, PixelFormat, ProResProfile, StillImageFormat, ToOptions, VideoImageFormat, X264Preset } from '@remotion/renderer';
1
+ import type { AudioCodec, ChromiumOptions, ColorSpace, FrameRange, LogLevel, PixelFormat, ProResProfile, StillImageFormat, ToOptions, VideoImageFormat, X264Preset } from '@remotion/renderer';
2
2
  import type { BrowserSafeApis } from '@remotion/renderer/client';
3
3
  import type { VideoConfig } from 'remotion';
4
4
  import type { ChunkRetry } from '../functions/helpers/get-retry-stats';
@@ -95,7 +95,8 @@ export declare enum LambdaRoutines {
95
95
  status = "status",
96
96
  renderer = "renderer",
97
97
  still = "still",
98
- compositions = "compositions"
98
+ compositions = "compositions",
99
+ merge = "merge"
99
100
  }
100
101
  type Prettify<T> = {
101
102
  [K in keyof T]: T[K];
@@ -264,7 +265,7 @@ export type LambdaPayloads = {
264
265
  timeoutInMilliseconds: number;
265
266
  chromiumOptions: ChromiumOptions;
266
267
  scale: number;
267
- downloadBehavior: DownloadBehavior | null;
268
+ downloadBehavior: DownloadBehavior;
268
269
  version: string;
269
270
  forceHeight: number | null;
270
271
  forceWidth: number | null;
@@ -284,6 +285,15 @@ export type LambdaPayloads = {
284
285
  bucketName: string | null;
285
286
  offthreadVideoCacheSizeInBytes: number | null;
286
287
  };
288
+ merge: {
289
+ type: LambdaRoutines.merge;
290
+ bucketName: string;
291
+ renderId: string;
292
+ outName: OutNameInput | null;
293
+ inputProps: SerializedInputProps;
294
+ serializedResolvedProps: SerializedInputProps;
295
+ verbose: boolean;
296
+ };
287
297
  };
288
298
  export type LambdaPayload = LambdaPayloads[LambdaRoutines];
289
299
  export type EncodingProgress = {
@@ -304,7 +314,7 @@ export type RenderMetadata = Discriminated & {
304
314
  estimatedTotalLambdaInvokations: number;
305
315
  estimatedRenderLambdaInvokations: number;
306
316
  compositionId: string;
307
- codec: Codec | null;
317
+ codec: LambdaCodec | null;
308
318
  audioCodec: AudioCodec | null;
309
319
  inputProps: SerializedInputProps;
310
320
  framesPerLambda: number;
@@ -317,6 +327,8 @@ export type RenderMetadata = Discriminated & {
317
327
  frameRange: [number, number];
318
328
  everyNthFrame: number;
319
329
  deleteAfter: DeleteAfter | null;
330
+ numberOfGifLoops: number | null;
331
+ downloadBehavior: DownloadBehavior;
320
332
  };
321
333
  export type AfterRenderCost = {
322
334
  estimatedCost: number;
@@ -103,6 +103,7 @@ var LambdaRoutines;
103
103
  LambdaRoutines["renderer"] = "renderer";
104
104
  LambdaRoutines["still"] = "still";
105
105
  LambdaRoutines["compositions"] = "compositions";
106
+ LambdaRoutines["merge"] = "merge";
106
107
  })(LambdaRoutines = exports.LambdaRoutines || (exports.LambdaRoutines = {}));
107
108
  exports.LAMBDA_CONCURRENCY_LIMIT_QUOTA = 'L-B99A9384';
108
109
  exports.LAMBDA_BURST_LIMIT_QUOTA = 'L-548AE339';
@@ -46,6 +46,9 @@ const isFlakyError = (err) => {
46
46
  if (message.includes('Timed out evaluating page function')) {
47
47
  return true;
48
48
  }
49
+ if (message.includes('Timeout exceeded rendering the component')) {
50
+ return true;
51
+ }
49
52
  // Internet flakiness
50
53
  if (message.includes('getaddrinfo') || message.includes('ECONNRESET')) {
51
54
  return true;
@@ -1,6 +1,7 @@
1
1
  import type { compositionsHandler } from '../functions/compositions';
2
2
  import type { infoHandler } from '../functions/info';
3
3
  import type { launchHandler } from '../functions/launch';
4
+ import type { mergeHandler } from '../functions/merge';
4
5
  import type { progressHandler } from '../functions/progress';
5
6
  import type { rendererHandler } from '../functions/renderer';
6
7
  import type { startHandler } from '../functions/start';
@@ -19,4 +20,5 @@ export interface LambdaReturnValues {
19
20
  [LambdaRoutines.info]: ReturnType<typeof infoHandler>;
20
21
  [LambdaRoutines.still]: ReturnType<typeof stillHandler>;
21
22
  [LambdaRoutines.compositions]: ReturnType<typeof compositionsHandler>;
23
+ [LambdaRoutines.merge]: ReturnType<typeof mergeHandler>;
22
24
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remotion/lambda",
3
- "version": "4.0.42",
3
+ "version": "4.0.44",
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/renderer": "4.0.42",
30
- "@remotion/bundler": "4.0.42",
31
- "remotion": "4.0.42",
32
- "@remotion/cli": "4.0.42"
29
+ "@remotion/bundler": "4.0.44",
30
+ "@remotion/renderer": "4.0.44",
31
+ "remotion": "4.0.44",
32
+ "@remotion/cli": "4.0.44"
33
33
  },
34
34
  "devDependencies": {
35
35
  "@jonny/eslint-config": "3.0.266",
@@ -43,11 +43,11 @@
43
43
  "ts-node": "^10.8.0",
44
44
  "vitest": "0.31.1",
45
45
  "zip-lib": "^0.7.2",
46
- "@remotion/bundler": "4.0.42",
47
- "@remotion/compositor-linux-arm64-gnu": "4.0.42"
46
+ "@remotion/bundler": "4.0.44",
47
+ "@remotion/compositor-linux-arm64-gnu": "4.0.44"
48
48
  },
49
49
  "peerDependencies": {
50
- "@remotion/bundler": "4.0.42"
50
+ "@remotion/bundler": "4.0.44"
51
51
  },
52
52
  "publishConfig": {
53
53
  "access": "public"
Binary file