Skip to content

Comments

feat: improve error handling, add timeouts and retry logic for chat c…#79

Closed
whereisfarukk wants to merge 1 commit intomainfrom
faruk/max-retry
Closed

feat: improve error handling, add timeouts and retry logic for chat c…#79
whereisfarukk wants to merge 1 commit intomainfrom
faruk/max-retry

Conversation

@whereisfarukk
Copy link
Collaborator

…ompletions

  • Add centralized error handling with handleRequestError() method
  • Implement model-specific timeouts for chat completions (5min for fast/auto, 3min for pro)
  • Add retry logic with exponential backoff for transient network errors
  • Remove console logging statements for production readiness
  • Simplify error handling while maintaining functionality

Fixes timeout issues with vlmrun-orion-1:fast and vlmrun-orion-1:auto models

…ompletions

- Add centralized error handling with handleRequestError() method
- Implement model-specific timeouts for chat completions (5min for fast/auto, 3min for pro)
- Add retry logic with exponential backoff for transient network errors
- Remove console logging statements for production readiness
- Simplify error handling while maintaining functionality

Fixes timeout issues with vlmrun-orion-1:fast and vlmrun-orion-1:auto models
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @whereisfarukk, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the reliability and stability of chat completion requests by implementing a comprehensive error handling strategy. It introduces centralized error processing, dynamic timeouts tailored to different models, and a robust retry mechanism for transient network issues. These changes aim to prevent common failures like timeouts and improve the overall user experience by making API interactions more resilient.

Highlights

  • Centralized Error Handling: A new private method, handleRequestError, has been introduced to centralize the processing and throwing of API errors, ensuring consistent error messages and removal of redundant error handling logic.
  • Model-Specific Timeouts: Chat completion requests now feature dynamic timeouts based on the model used: 5 minutes for 'fast' and 'auto' models, and 3 minutes for 'pro' models, addressing previous timeout issues.
  • Retry Logic with Exponential Backoff: Transient network errors (e.g., ETIMEDOUT, ECONNRESET) are now handled with a retry mechanism that includes exponential backoff, improving the robustness of API calls.
  • Production Readiness: All console.log statements have been removed, making the code cleaner and more suitable for production environments.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces significant improvements to error handling, timeouts, and retry logic, enhancing the robustness of the client. The introduction of a centralized handleRequestError method is a good step towards cleaner code.

My review includes a few suggestions:

  • A critical fix for the retry logic to prevent premature termination and ensure it correctly handles retries and throws the final error.
  • A suggestion to remove unused parameters from the new error handling function for code clarity.
  • A recommendation to replace magic numbers for timeouts with named constants for better readability and maintainability.

Overall, these changes are valuable, and with the suggested adjustments, the implementation will be more robust and maintainable.

Comment on lines +212 to 248
// Add retry logic for transient network errors
let lastError: any;
const maxRetries = 3;

for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const response = await this.ef.helpers.httpRequestWithAuthentication.call(
this.ef,
'vlmRunApi',
options,
);
return response;
} catch (error: any) {
lastError = error;

// Check if it's a retryable error (network/timeout errors)
const errorCode = error.code || error.cause?.code;
const isRetryable =
errorCode === 'ETIMEDOUT' ||
errorCode === 'ECONNRESET' ||
errorCode === 'EPIPE' ||
(!error.response && attempt < maxRetries); // Network errors without response

if (isRetryable && attempt < maxRetries) {
const delay = RETRY_DELAY * attempt; // Exponential backoff
await new Promise(resolve => setTimeout(resolve, delay));
continue;
}

// Not retryable or max retries reached
this.handleRequestError(error, url, method);
}
throw new Error(`HTTP ${error.response?.status || 'Error'}: ${errorDetail}`);
}

// All retries exhausted
this.handleRequestError(lastError, url, method);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

The current retry logic has a flaw. The call to this.handleRequestError(error, url, method); on line 242 will always throw an exception, causing the function to exit immediately. This makes the code on line 247 (this.handleRequestError(lastError, url, method);) unreachable. Consequently, the function might not wait for all retries to be exhausted and might report an intermediate error instead of the last one.

The retry logic should be refactored to only continue the loop for retryable errors within the retry limit. If an error is not retryable, or if the maximum number of retries has been reached, the loop should be exited, and then the lastError should be thrown.

		// Add retry logic for transient network errors
		let lastError: any;
		const maxRetries = 3;

		for (let attempt = 1; attempt <= maxRetries; attempt++) {
			try {
				const response = await this.ef.helpers.httpRequestWithAuthentication.call(
					this.ef,
					'vlmRunApi',
					options,
				);
				return response;
			} catch (error: any) {
				lastError = error;

				// Check if it's a retryable error (network/timeout errors)
				const errorCode = error.code || error.cause?.code;
				const isRetryable =
					errorCode === 'ETIMEDOUT' ||
					errorCode === 'ECONNRESET' ||
					errorCode === 'EPIPE' ||
					!error.response; // Network errors without response

				if (isRetryable && attempt < maxRetries) {
					const delay = RETRY_DELAY * attempt; // Exponential backoff
					await new Promise(resolve => setTimeout(resolve, delay));
					continue;
				}

				// Not retryable or max retries reached, so break the loop
				break;
			}
		}

		// All retries exhausted or a non-retryable error occurred
		this.handleRequestError(lastError, url, method);
	}

: config.agentBaseURL;
}

private handleRequestError(error: any, url: string, method: string): never {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The url and method parameters in handleRequestError are not used within the function. This can be misleading. If they are not needed, they should be removed to simplify the function signature. This would also require updating the call sites in makeRequest and makeAgentRequest.

Suggested change
private handleRequestError(error: any, url: string, method: string): never {
private handleRequestError(error: any): never {

Comment on lines +177 to +185
let timeout = 60000; // Default 60 seconds
if (endpoint === '/openai/chat/completions' && data?.model) {
// Chat completions need longer timeout
// "fast" and "auto" models might need more time than "pro"
if (data.model.includes(':fast') || data.model.includes(':auto')) {
timeout = 300000; // 5 minutes for fast/auto
} else {
timeout = 180000; // 3 minutes for pro
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The timeout values 60000, 300000, and 180000 are used as magic numbers. It would be better to define them as named constants at the top of the file or in config.ts for better readability and maintainability. This makes it easier to understand their purpose and modify them in one place if needed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant