Skip to content

Commit c78f84b

Browse files
fix: gracefully abort the run when Apify Proxy is unusable (#137)
* fix: gracefully abort the run when Apify Proxy is unusable * chore: exit the Actor instead of waiting to be killed * chore: remove validation of proxy configuration
1 parent 9a001c5 commit c78f84b

2 files changed

Lines changed: 27 additions & 2 deletions

File tree

src/input.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import type {
1919
SERPProxyGroup,
2020
UrlToMarkdownInput,
2121
} from './types.js';
22+
import { abortRun } from './utils.js';
2223

2324
/**
2425
* Processes the input and returns an array of crawler settings. This is ideal for startup of STANDBY mode
@@ -27,7 +28,7 @@ import type {
2728
export async function processStandbyInput(originalInput: Partial<Input>) {
2829
const { input, searchCrawlerOptions, contentScraperSettings } = await processInputInternal(originalInput, true);
2930

30-
const proxy = await Actor.createProxyConfiguration(input.proxyConfiguration);
31+
const proxy = await createContentProxyConfiguration(input.proxyConfiguration);
3132
const contentCrawlerOptions: ContentCrawlerOptions[] = [
3233
createPlaywrightCrawlerOptions(input, proxy),
3334
createCheerioCrawlerOptions(input, proxy),
@@ -42,7 +43,7 @@ export async function processStandbyInput(originalInput: Partial<Input>) {
4243
export async function processInput(originalInput: Partial<Input>) {
4344
const { input, searchCrawlerOptions, contentScraperSettings } = await processInputInternal(originalInput);
4445

45-
const proxy = await Actor.createProxyConfiguration(input.proxyConfiguration);
46+
const proxy = await createContentProxyConfiguration(input.proxyConfiguration);
4647
const contentCrawlerOptions: ContentCrawlerOptions = input.scrapingTool === 'raw-http'
4748
? createCheerioCrawlerOptions(input, proxy, false)
4849
: createPlaywrightCrawlerOptions(input, proxy, false);
@@ -210,6 +211,14 @@ async function processUrlToMarkdownInput(input: Partial<UrlToMarkdownInput>): Pr
210211
return validatedInput;
211212
}
212213

214+
async function createContentProxyConfiguration(proxyConfiguration: ProxyConfigurationOptions) {
215+
try {
216+
return await Actor.createProxyConfiguration(proxyConfiguration);
217+
} catch (e) {
218+
return abortRun(`Cannot use Apify Proxy for scraping the target pages: ${(e as Error).message}`);
219+
}
220+
}
221+
213222
function createPlaywrightCrawlerOptions(
214223
input: Input,
215224
proxy: ProxyConfiguration | undefined,

src/utils.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,22 @@ export function isActorStandby(): boolean {
4747
return Actor.getEnv().metaOrigin === 'STANDBY';
4848
}
4949

50+
/**
51+
* Aborts the run with a terminal status message, instead of crashing or failing it.
52+
*/
53+
export async function abortRun(statusMessage: string): Promise<never> {
54+
log.error(statusMessage);
55+
56+
if (!Actor.isAtHome()) {
57+
process.exit(1);
58+
}
59+
60+
// Aborting gracefully buys the 30 seconds that the teardown needs before the container is stopped.
61+
await Actor.abort(Actor.getEnv().actorRunId!, { statusMessage, gracefully: true });
62+
await Actor.exit({ exit: false });
63+
process.exit(0);
64+
}
65+
5066
/**
5167
* Extracts the calling end-user's authorization from the x-apify-user-authorization header.
5268
* Node lower-cases header names, and the header could theoretically arrive as a string array.

0 commit comments

Comments
 (0)