@remotion/lambda 4.0.65 → 4.0.67

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.
@@ -21,10 +21,10 @@ const waitForLaunched = () => {
21
21
  return new Promise((resolve, reject) => {
22
22
  const check = () => setTimeout(() => {
23
23
  if (launching) {
24
- resolve();
24
+ check();
25
25
  }
26
26
  else {
27
- check();
27
+ resolve();
28
28
  }
29
29
  }, 16);
30
30
  setTimeout(() => reject(new Error('Timeout launching browser')), 5000);
@@ -32,7 +32,7 @@ const waitForLaunched = () => {
32
32
  });
33
33
  };
34
34
  const forgetBrowserEventLoop = (logLevel) => {
35
- renderer_1.RenderInternals.Log.verbose({ indent: false, logLevel }, 'Keeping browser open for next invocation');
35
+ renderer_1.RenderInternals.Log.infoAdvanced({ indent: false, logLevel }, 'Keeping browser open for next invocation');
36
36
  _browserInstance === null || _browserInstance === void 0 ? void 0 : _browserInstance.instance.forgetEventLoop();
37
37
  };
38
38
  exports.forgetBrowserEventLoop = forgetBrowserEventLoop;
@@ -43,6 +43,7 @@ const getBrowserInstance = async (logLevel, indent, chromiumOptions) => {
43
43
  // Override the `null` value, which might come from CLI with swANGLE
44
44
  gl: (_a = chromiumOptions.gl) !== null && _a !== void 0 ? _a : 'swangle',
45
45
  };
46
+ const configurationString = makeConfigurationString(actualChromiumOptions, logLevel);
46
47
  if (launching) {
47
48
  renderer_1.RenderInternals.Log.info('Already waiting for browser launch...');
48
49
  await waitForLaunched();
@@ -50,7 +51,6 @@ const getBrowserInstance = async (logLevel, indent, chromiumOptions) => {
50
51
  throw new Error('expected to launch');
51
52
  }
52
53
  }
53
- const configurationString = makeConfigurationString(actualChromiumOptions, logLevel);
54
54
  if (!_browserInstance) {
55
55
  renderer_1.RenderInternals.Log.info('Cold Lambda function, launching new Lambda function');
56
56
  launching = true;
@@ -1 +1 @@
1
- export declare const getCurrentRegionInFunction: () => "eu-central-1" | "eu-west-1" | "eu-west-2" | "eu-west-3" | "eu-north-1" | "us-east-1" | "us-east-2" | "us-west-1" | "us-west-2" | "ap-south-1" | "ap-southeast-1" | "ap-southeast-2" | "ap-northeast-1" | "ap-northeast-2" | "ap-northeast-3" | "ca-central-1" | "sa-east-1" | "eu-south-1" | "af-south-1" | "ap-east-1" | "me-south-1";
1
+ export declare const getCurrentRegionInFunction: () => "eu-central-1" | "eu-west-1" | "eu-west-2" | "eu-west-3" | "eu-south-1" | "eu-north-1" | "us-east-1" | "us-east-2" | "us-west-1" | "us-west-2" | "af-south-1" | "ap-south-1" | "ap-east-1" | "ap-southeast-1" | "ap-southeast-2" | "ap-northeast-1" | "ap-northeast-2" | "ap-northeast-3" | "ca-central-1" | "me-south-1" | "sa-east-1";
@@ -0,0 +1,4 @@
1
+ import type { NodeIntrospection } from '../../shared/why-is-node-running';
2
+ export declare const stopLeakDetection: () => void;
3
+ export declare const setCurrentRequestId: (awsRequestId: string) => void;
4
+ export declare const startLeakDetection: (leakDetection: NodeIntrospection, awsRequestId: string) => void;
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.startLeakDetection = exports.setCurrentRequestId = exports.stopLeakDetection = void 0;
4
+ const why_is_node_running_1 = require("../../shared/why-is-node-running");
5
+ let currentRequestId = null;
6
+ let leakDetectionTimeout = null;
7
+ const stopLeakDetection = () => {
8
+ if (leakDetectionTimeout !== null) {
9
+ clearTimeout(leakDetectionTimeout.timeout);
10
+ leakDetectionTimeout = null;
11
+ }
12
+ };
13
+ exports.stopLeakDetection = stopLeakDetection;
14
+ const setCurrentRequestId = (awsRequestId) => {
15
+ currentRequestId = awsRequestId;
16
+ };
17
+ exports.setCurrentRequestId = setCurrentRequestId;
18
+ const startLeakDetection = (leakDetection, awsRequestId) => {
19
+ currentRequestId = awsRequestId;
20
+ leakDetectionTimeout = {
21
+ awsRequestId,
22
+ timeout: setTimeout(() => {
23
+ // First allow request ID to be set
24
+ setTimeout(() => {
25
+ if (currentRequestId !== awsRequestId) {
26
+ // New function, all good
27
+ return;
28
+ }
29
+ console.log('Leak detected: Lambda function is still running 10s after the render has finished.');
30
+ console.log('You may report this to the Remotion team.');
31
+ console.log('Include the logs below:');
32
+ (0, why_is_node_running_1.whyIsNodeRunning)(leakDetection);
33
+ console.log('Force-quitting the Lambda function now.');
34
+ process.exit(0);
35
+ }, 100);
36
+ }, 10000),
37
+ };
38
+ leakDetectionTimeout.timeout.unref();
39
+ };
40
+ exports.startLeakDetection = startLeakDetection;
@@ -0,0 +1,5 @@
1
+ export type RequestContext = {
2
+ invokedFunctionArn: string;
3
+ getRemainingTimeInMillis: () => number;
4
+ awsRequestId: string;
5
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -4,16 +4,16 @@ declare const streamingPayloadSchema: z.ZodDiscriminatedUnion<"type", [z.ZodObje
4
4
  type: z.ZodLiteral<"render-id-determined">;
5
5
  renderId: z.ZodString;
6
6
  }, "strip", z.ZodTypeAny, {
7
- renderId: string;
8
7
  type: "render-id-determined";
9
- }, {
10
8
  renderId: string;
9
+ }, {
11
10
  type: "render-id-determined";
11
+ renderId: string;
12
12
  }>]>;
13
13
  export type StreamingPayloads = z.infer<typeof streamingPayloadSchema>;
14
14
  export declare const isStreamingPayload: (str: string) => false | {
15
- renderId: string;
16
15
  type: "render-id-determined";
16
+ renderId: string;
17
17
  };
18
18
  export declare const sendProgressEvent: (responseStream: ResponseStream, payload: StreamingPayloads) => void;
19
19
  export {};
@@ -6,6 +6,7 @@ const constants_1 = require("../shared/constants");
6
6
  const compositions_1 = require("./compositions");
7
7
  const clean_tmpdir_1 = require("./helpers/clean-tmpdir");
8
8
  const is_warm_1 = require("./helpers/is-warm");
9
+ const leak_detection_1 = require("./helpers/leak-detection");
9
10
  const lifecycle_1 = require("./helpers/lifecycle");
10
11
  const print_cloudwatch_helper_1 = require("./helpers/print-cloudwatch-helper");
11
12
  const streamify_response_1 = require("./helpers/streamify-response");
@@ -18,8 +19,11 @@ const renderer_2 = require("./renderer");
18
19
  const start_1 = require("./start");
19
20
  const still_1 = require("./still");
20
21
  const innerHandler = async (params, responseStream, context) => {
22
+ (0, leak_detection_1.setCurrentRequestId)(context.awsRequestId);
21
23
  process.env.__RESERVED_IS_INSIDE_REMOTION_LAMBDA = 'true';
22
24
  const timeoutInMilliseconds = context.getRemainingTimeInMillis();
25
+ console.log('AWS Request ID:', context.awsRequestId);
26
+ (0, leak_detection_1.stopLeakDetection)();
23
27
  if (!(context === null || context === void 0 ? void 0 : context.invokedFunctionArn)) {
24
28
  throw new Error('Lambda function unexpectedly does not have context.invokedFunctionArn');
25
29
  }
@@ -108,7 +112,7 @@ const innerHandler = async (params, responseStream, context) => {
108
112
  const response = await (0, renderer_2.rendererHandler)(params, {
109
113
  expectedBucketOwner: currentUserId,
110
114
  isWarm,
111
- });
115
+ }, context);
112
116
  responseStream.write(JSON.stringify(response), () => {
113
117
  responseStream.end();
114
118
  });
@@ -1,9 +1,10 @@
1
1
  import type { LambdaPayload } from '../shared/constants';
2
+ import type { RequestContext } from './helpers/request-context';
2
3
  type Options = {
3
4
  expectedBucketOwner: string;
4
5
  isWarm: boolean;
5
6
  };
6
- export declare const rendererHandler: (params: LambdaPayload, options: Options) => Promise<{
7
+ export declare const rendererHandler: (params: LambdaPayload, options: Options, requestContext: RequestContext) => Promise<{
7
8
  type: 'success';
8
9
  }>;
9
10
  export {};
@@ -13,10 +13,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
15
  const is_flaky_error_1 = require("../shared/is-flaky-error");
16
+ const why_is_node_running_1 = require("../shared/why-is-node-running");
16
17
  const get_browser_instance_1 = require("./helpers/get-browser-instance");
17
18
  const get_chromium_executable_path_1 = require("./helpers/get-chromium-executable-path");
18
19
  const get_current_region_1 = require("./helpers/get-current-region");
19
20
  const io_1 = require("./helpers/io");
21
+ const leak_detection_1 = require("./helpers/leak-detection");
20
22
  const on_downloads_logger_1 = require("./helpers/on-downloads-logger");
21
23
  const write_lambda_error_1 = require("./helpers/write-lambda-error");
22
24
  const renderHandler = async (params, options, logs) => {
@@ -212,11 +214,12 @@ const renderHandler = async (params, options, logs) => {
212
214
  renderer_1.RenderInternals.Log.verbose({ indent: false, logLevel: params.logLevel }, 'Done!');
213
215
  return {};
214
216
  };
215
- const rendererHandler = async (params, options) => {
217
+ const rendererHandler = async (params, options, requestContext) => {
216
218
  if (params.type !== constants_1.LambdaRoutines.renderer) {
217
219
  throw new Error('Params must be renderer');
218
220
  }
219
221
  const logs = [];
222
+ const leakDetection = (0, why_is_node_running_1.enableNodeIntrospection)();
220
223
  try {
221
224
  await renderHandler(params, options, logs);
222
225
  return {
@@ -275,6 +278,7 @@ const rendererHandler = async (params, options) => {
275
278
  }
276
279
  finally {
277
280
  (0, get_browser_instance_1.forgetBrowserEventLoop)(params.logLevel);
281
+ (0, leak_detection_1.startLeakDetection)(leakDetection, requestContext.awsRequestId);
278
282
  }
279
283
  };
280
284
  exports.rendererHandler = rendererHandler;
@@ -1,5 +1,5 @@
1
1
  export declare const LambdaInternals: {
2
- executeCommand: (args: string[], remotionRoot: string, logLevel: "error" | "verbose" | "info" | "warn") => Promise<void>;
2
+ executeCommand: (args: string[], remotionRoot: string, logLevel: "verbose" | "info" | "warn" | "error") => Promise<void>;
3
3
  makeLambdaRenderMediaPayload: ({ rendererFunctionName, frameRange, framesPerLambda, forceBucketName: bucketName, codec, composition, serveUrl, imageFormat, inputProps, region, crf, envVariables, pixelFormat, proResProfile, x264Preset, maxRetries, privacy, logLevel, outName, timeoutInMilliseconds, chromiumOptions, scale, everyNthFrame, numberOfGifLoops, audioBitrate, concurrencyPerLambda, audioCodec, forceHeight, forceWidth, webhook, videoBitrate, downloadBehavior, muted, overwrite, jpegQuality, offthreadVideoCacheSizeInBytes, deleteAfter, colorSpace, }: import("./api/make-lambda-payload").InnerRenderMediaOnLambdaInput) => Promise<import("./defaults").LambdaStartPayload>;
4
4
  getRenderProgressPayload: ({ bucketName, renderId, s3OutputProvider, }: import(".").GetRenderProgressInput) => import("./defaults").LambdaStatusPayload;
5
5
  };
@@ -0,0 +1,10 @@
1
+ /// <reference types="node" />
2
+ /// <reference types="node" />
3
+ /// <reference types="node" />
4
+ /// <reference types="node" />
5
+ export declare const stackback: (error: Error) => NodeJS.CallSite[];
6
+ declare global {
7
+ interface Error {
8
+ _sb_callsites: NodeJS.CallSite[];
9
+ }
10
+ }
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.stackback = void 0;
4
+ function FormatStackTrace(error, frames) {
5
+ const lines = [];
6
+ try {
7
+ lines.push(error.toString());
8
+ }
9
+ catch (e) {
10
+ try {
11
+ lines.push('<error: ' + e + '>');
12
+ }
13
+ catch (ee) {
14
+ lines.push('<error>');
15
+ }
16
+ }
17
+ for (let i = 0; i < frames.length; i++) {
18
+ const frame = frames[i];
19
+ let line;
20
+ try {
21
+ line = frame.toString();
22
+ }
23
+ catch (e) {
24
+ try {
25
+ line = '<error: ' + e + '>';
26
+ }
27
+ catch (ee) {
28
+ // Any code that reaches this point is seriously nasty!
29
+ line = '<error>';
30
+ }
31
+ }
32
+ lines.push(' at ' + line);
33
+ }
34
+ return lines.join('\n');
35
+ }
36
+ const stackback = (error) => {
37
+ // save original stacktrace
38
+ const save = Error.prepareStackTrace;
39
+ // replace capture with our function
40
+ Error.prepareStackTrace = function (err, trace) {
41
+ // cache stack frames so we don't have to get them again
42
+ // use a non-enumerable property
43
+ Object.defineProperty(err, '_sb_callsites', {
44
+ value: trace,
45
+ });
46
+ return (save || FormatStackTrace)(err, trace);
47
+ };
48
+ // force capture of the stack frames
49
+ // eslint-disable-next-line no-unused-expressions
50
+ error.stack;
51
+ // someone already asked for the stack so we can't do this trick
52
+ if (!error._sb_callsites) {
53
+ return [];
54
+ }
55
+ // return original capture function
56
+ Error.prepareStackTrace = save;
57
+ return error._sb_callsites;
58
+ };
59
+ exports.stackback = stackback;
@@ -0,0 +1,17 @@
1
+ /// <reference types="node" />
2
+ /// <reference types="node" />
3
+ import asyncHooks from 'async_hooks';
4
+ type Resource = {
5
+ type: string;
6
+ stacks: NodeJS.CallSite[];
7
+ resource: {
8
+ hasRef?: () => boolean;
9
+ };
10
+ };
11
+ export type NodeIntrospection = {
12
+ hook: asyncHooks.AsyncHook;
13
+ active: Map<number, Resource>;
14
+ };
15
+ export declare const enableNodeIntrospection: () => NodeIntrospection;
16
+ export declare function whyIsNodeRunning({ active, hook }: NodeIntrospection): void;
17
+ export {};
@@ -0,0 +1,79 @@
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.whyIsNodeRunning = exports.enableNodeIntrospection = void 0;
7
+ const async_hooks_1 = __importDefault(require("async_hooks"));
8
+ const fs_1 = __importDefault(require("fs"));
9
+ const path_1 = require("path");
10
+ const stackback_1 = require("./stackback");
11
+ const enableNodeIntrospection = () => {
12
+ const active = new Map();
13
+ const hook = async_hooks_1.default.createHook({
14
+ init(asyncId, type, _triggerAsyncId, resource) {
15
+ if (type === 'TIMERWRAP' || type === 'PROMISE')
16
+ return;
17
+ if (type === 'PerformanceObserver' || type === 'RANDOMBYTESREQUEST')
18
+ return;
19
+ const err = new Error('whatevs');
20
+ const stacks = (0, stackback_1.stackback)(err);
21
+ active.set(asyncId, { type, stacks, resource });
22
+ },
23
+ destroy(asyncId) {
24
+ active.delete(asyncId);
25
+ },
26
+ });
27
+ hook.enable();
28
+ return { hook, active };
29
+ };
30
+ exports.enableNodeIntrospection = enableNodeIntrospection;
31
+ function whyIsNodeRunning({ active, hook }) {
32
+ hook.disable();
33
+ const activeResources = [...active.values()].filter((r) => {
34
+ if (typeof r.resource.hasRef === 'function' && !r.resource.hasRef())
35
+ return false;
36
+ return true;
37
+ });
38
+ console.error('There are %d handle(s) keeping the process running', activeResources.length);
39
+ function printStacks(o) {
40
+ const stacks = o.stacks.slice(1).filter((s) => {
41
+ const filename = s.getFileName();
42
+ return (filename &&
43
+ filename.indexOf(path_1.sep) > -1 &&
44
+ filename.indexOf('internal' + path_1.sep) !== 0);
45
+ });
46
+ console.error('');
47
+ console.error('# %s', o.type);
48
+ if (stacks[0]) {
49
+ let padding = '';
50
+ stacks.forEach((s) => {
51
+ const pad = (s.getFileName() + ':' + s.getLineNumber()).replace(/./g, ' ');
52
+ if (pad.length > padding.length)
53
+ padding = pad;
54
+ });
55
+ stacks.forEach((s) => {
56
+ const prefix = s.getFileName() + ':' + s.getLineNumber();
57
+ try {
58
+ const src = fs_1.default
59
+ .readFileSync(s.getFileName(), 'utf-8')
60
+ .split(/\n|\r\n/);
61
+ console.error(prefix +
62
+ padding.slice(prefix.length) +
63
+ ' - ' +
64
+ src[s.getLineNumber() - 1].trim());
65
+ }
66
+ catch (e) {
67
+ console.error(prefix + padding.slice(prefix.length));
68
+ }
69
+ });
70
+ }
71
+ else {
72
+ console.error('(unknown stack trace)');
73
+ }
74
+ }
75
+ for (const o of activeResources) {
76
+ printStacks(o);
77
+ }
78
+ }
79
+ exports.whyIsNodeRunning = whyIsNodeRunning;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remotion/lambda",
3
- "version": "4.0.65",
3
+ "version": "4.0.67",
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.22.3",
29
- "@remotion/bundler": "4.0.65",
30
- "@remotion/cli": "4.0.65",
31
- "@remotion/renderer": "4.0.65",
32
- "remotion": "4.0.65"
29
+ "@remotion/bundler": "4.0.67",
30
+ "@remotion/cli": "4.0.67",
31
+ "@remotion/renderer": "4.0.67",
32
+ "remotion": "4.0.67"
33
33
  },
34
34
  "devDependencies": {
35
35
  "@jonny/eslint-config": "3.0.276",
@@ -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/compositor-linux-arm64-gnu": "4.0.65",
47
- "@remotion/bundler": "4.0.65"
46
+ "@remotion/bundler": "4.0.67",
47
+ "@remotion/compositor-linux-arm64-gnu": "4.0.67"
48
48
  },
49
49
  "peerDependencies": {
50
- "@remotion/bundler": "4.0.65"
50
+ "@remotion/bundler": "4.0.67"
51
51
  },
52
52
  "publishConfig": {
53
53
  "access": "public"
Binary file