Skip to content

Commit fb36772

Browse files
fix: improve retry logging (#82)
This PR is a clone of Unstructured-IO/unstructured-python-client#111 ### Summary - remove false success log in split-page after error hook - moves success/failure logs to the LoggerHook
1 parent a899c14 commit fb36772

File tree

5 files changed

+92
-55
lines changed

5 files changed

+92
-55
lines changed

src/hooks/custom/LogRetryHook.ts

-46
This file was deleted.

src/hooks/custom/LoggerHook.ts

+82
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import { AfterErrorContext, AfterErrorHook, AfterSuccessContext, AfterSuccessHook } from "../types";
2+
3+
/**
4+
* Represents a hook that logs status and information that the request will be retried
5+
* after encountering a 5xx error.
6+
*/
7+
export class LoggerHook implements AfterSuccessHook, AfterErrorHook {
8+
private retriesCounter: Map<string, number> = new Map();
9+
10+
/**
11+
* Log retries to give users visibility into requests.
12+
* @param response - The response object received from the server.
13+
* @param error - The error object representing the encountered error.
14+
* @param operationID - The unique identifier for the operation being logged.
15+
*/
16+
private logRetries(
17+
response: Response | null,
18+
error: unknown,
19+
operationID: string
20+
): void {
21+
if (response && response.status >= 500) {
22+
console.warn(
23+
"Failed to process a request due to API server error with status code %d. " +
24+
"Attempting retry number %d after sleep.",
25+
response.status,
26+
this.retriesCounter.get(operationID)
27+
);
28+
if (response.statusText) {
29+
console.warn("Server message - %s", response.statusText);
30+
}
31+
} else if (error) {
32+
console.info(
33+
`Failed to process a request due to connection error - ${(error as Error).message}. ` +
34+
`Attempting retry number ${this.retriesCounter.get(operationID)} after sleep.`
35+
);
36+
}
37+
}
38+
39+
/**
40+
* Handles successful responses, resetting the retry counter for the operation.
41+
* Logs a success message indicating that the document was successfully partitioned.
42+
* @param hookCtx - The context object containing information about the request.
43+
* @param response - The response object received from the server.
44+
* @returns The response object.
45+
*/
46+
afterSuccess(hookCtx: AfterSuccessContext, response: Response): Response {
47+
this.retriesCounter.delete(hookCtx.operationID);
48+
// NOTE: In case of split page partition this means - at least one of the splits was partitioned successfully
49+
console.info("Successfully partitioned the document.");
50+
return response;
51+
}
52+
53+
/**
54+
* Executes after an error occurs during a request.
55+
* @param hookCtx - The context object containing information about the request.
56+
* @param response - The response object received from the server.
57+
* @param error - The error object representing the encountered error.
58+
* @returns An object containing the updated response and error.
59+
*/
60+
afterError(
61+
hookCtx: AfterErrorContext,
62+
response: Response | null,
63+
error: unknown
64+
): { response: Response | null; error: unknown } {
65+
const currentCount = this.retriesCounter.get(hookCtx.operationID) || 0;
66+
this.retriesCounter.set(hookCtx.operationID, currentCount + 1);
67+
this.logRetries(response, error, hookCtx.operationID);
68+
69+
if (response && response.status === 200) {
70+
console.info("Successfully partitioned the document.");
71+
} else {
72+
console.error("Failed to partition the document.");
73+
if (response) {
74+
console.error(`Server responded with ${response.status} - ${response.statusText}`);
75+
}
76+
if (error) {
77+
console.error(`Following error occurred - ${(error as Error).message}`);
78+
}
79+
}
80+
return { response, error };
81+
}
82+
}

src/hooks/custom/SplitPdfHook.ts

-4
Original file line numberDiff line numberDiff line change
@@ -213,8 +213,6 @@ export class SplitPdfHook
213213

214214
this.clearOperation(operationID);
215215

216-
console.info("Successfully processed the request.")
217-
218216
return new Response(body, {
219217
headers: headers,
220218
status: response.status,
@@ -241,7 +239,6 @@ export class SplitPdfHook
241239
const responses = await this.awaitAllRequests(operationID);
242240

243241
if (!responses?.length) {
244-
console.error("Failed to process the request.");
245242
this.clearOperation(operationID);
246243
return { response, error };
247244
}
@@ -257,7 +254,6 @@ export class SplitPdfHook
257254
});
258255

259256
this.clearOperation(operationID);
260-
console.info("Successfully processed the request.");
261257

262258
return { response: finalResponse, error: null };
263259
}

src/hooks/registration.ts

+7-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Hooks } from "./types";
22

3-
import { LogRetryHook } from "./custom/LogRetryHook";
3+
import { LoggerHook } from "./custom/LoggerHook";
44
import { SplitPdfHook } from "./custom/SplitPdfHook";
55
import { HttpsCheckHook } from "./custom/HttpsCheckHook";
66

@@ -16,10 +16,13 @@ export function initHooks(hooks: Hooks) {
1616
// Hooks are registered per SDK instance, and are valid for the lifetime of the SDK instance
1717

1818
// Initialize hooks
19-
const logErrorHook = new LogRetryHook();
19+
const loggerHook = new LoggerHook();
2020
const splitPdfHook = new SplitPdfHook();
2121
const httpsCheckHook = new HttpsCheckHook();
2222

23+
// NOTE: logger_hook should stay registered last as logs the status of
24+
// request and whether it will be retried which can be changed by e.g. split_pdf_hook
25+
2326
// Register SDK init hooks
2427
hooks.registerSDKInitHook(httpsCheckHook);
2528
hooks.registerSDKInitHook(splitPdfHook);
@@ -29,8 +32,9 @@ export function initHooks(hooks: Hooks) {
2932

3033
// Register after success hooks
3134
hooks.registerAfterSuccessHook(splitPdfHook);
35+
hooks.registerAfterSuccessHook(loggerHook)
3236

3337
// Register after error hooks
3438
hooks.registerAfterErrorHook(splitPdfHook);
35-
hooks.registerAfterErrorHook(logErrorHook);
39+
hooks.registerAfterErrorHook(loggerHook);
3640
}

test/integration/SplitPdfHook.test.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -170,8 +170,9 @@ describe("SplitPdfHook integration tests check splitted file is same as not spli
170170
});
171171
} catch (e) {
172172
if (!expectedOk) {
173-
expect(consoleErrorSpy).toHaveBeenCalledTimes(2);
174-
expect(consoleErrorSpy).toHaveBeenCalledWith("Failed to process the request.");
173+
expect(consoleErrorSpy).toHaveBeenCalledTimes(3);
174+
expect(consoleErrorSpy).toHaveBeenCalledWith("Failed to partition the document.");
175+
expect(consoleErrorSpy).toHaveBeenCalledWith(expect.stringContaining("Server responded with"));
175176
expect(consoleWarnSpy).toHaveBeenCalledWith(
176177
"Attempted to interpret file as pdf, but error arose when splitting by pages. Reverting to non-split pdf handling path."
177178
);

0 commit comments

Comments
 (0)