Skip to content

Choosing Whether to Enable Retries in Firebase App Options #1075

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
ksiisk99 opened this issue Feb 12, 2025 · 2 comments
Open

Choosing Whether to Enable Retries in Firebase App Options #1075

ksiisk99 opened this issue Feb 12, 2025 · 2 comments

Comments

@ksiisk99
Copy link

Hello,
I have learned that FCM automatically retries when a 503 response is received.
However, our service already handles retries for undelivered messages through scheduling, so we do not want to use the default retry strategy.

public static HttpRequestFactory newAuthorizedRequestFactory(
	FirebaseApp app, @Nullable RetryConfig retryConfig) {
	HttpTransport transport = app.getOptions().getHttpTransport();
	return transport.createRequestFactory(new FirebaseRequestInitializer(app, retryConfig));
}

To disable this behavior, I attempted to use a method provided in the ApiClientUtils class.
However, after debugging the initialization process, I found that it is not possible to set a custom RetryConfig value.

I assume there is a valid reason for restricting the redefinition of RetryConfig.
For example, it may be to prevent retries for responses other than 5xx errors or to avoid excessive retry requests within a short period.

What I would like is the ability to enable or disable the retry feature as needed.
I will proceed with creating a PR for this.

@google-oss-bot
Copy link

I couldn't figure out how to label this issue, so I've labeled it for a human to triage. Hang tight.

@Mohima6
Copy link

Mohima6 commented Mar 21, 2025

Root Cause:
The Firebase Cloud Messaging (FCM) library automatically retries requests when a 503 response is received, which might not always align with the specific retry strategies required by the application. This behavior is implemented by default to ensure reliable message delivery, but it may conflict with custom retry handling strategies already in place, like scheduled retries within the service. The issue arises because the retry configuration (RetryConfig) is not exposed for customization in the current Firebase SDK, thus preventing users from disabling or modifying the retry behavior directly. To address the issue in #1075 (Choosing Whether to Enable Retries in Firebase App Options), you would need to modify how the retry configuration is applied in the Firebase SDK, particularly in the method that handles retries for Firebase Cloud Messaging (FCM).

Step 1: Modify FirebaseAppOptions to Accept RetryConfig--

You’ll want to allow RetryConfig to be passed when initializing Firebase. This can be added to the FirebaseAppOptions class. For this, you will need to expose a method to set or get the retry configuration.

public class FirebaseAppOptions {

private RetryConfig retryConfig;

// Add a getter and setter for retryConfig
public RetryConfig getRetryConfig() {
    return retryConfig;
}

public void setRetryConfig(RetryConfig retryConfig) {
    this.retryConfig = retryConfig;
}

}

Step 2: Update the Method to Use the RetryConfig from FirebaseAppOptions

Now, update the part of the code that sends requests and retries in Firebase Cloud Messaging, ensuring that the retry configuration can be customized.
public static HttpRequestFactory newAuthorizedRequestFactory(
FirebaseApp app, @nullable RetryConfig retryConfig) {

HttpTransport transport = app.getOptions().getHttpTransport();

// If a custom retry config is provided, use it
if (retryConfig != null) {
    return transport.createRequestFactory(new FirebaseRequestInitializer(app, retryConfig));
} else {
    // Default behavior, or disable retries
    return transport.createRequestFactory(new FirebaseRequestInitializer(app, new RetryConfig(0))); // No retries
}

}

Step 3: Update the Logic to Disable or Customize Retries

Modify the retry handling logic to account for the RetryConfig passed during initialization. This would allow the app to customize or disable retries based on user preferences.
public class FirebaseRequestInitializer extends HttpRequestInitializer {

private final RetryConfig retryConfig;

public FirebaseRequestInitializer(FirebaseApp app, RetryConfig retryConfig) {
    this.retryConfig = retryConfig;
}

@Override
public void initialize(HttpRequest request) throws IOException {
    if (retryConfig != null && retryConfig.getMaxRetries() == 0) {
        // Disable retries
        request.setReadTimeout(0); // Optionally adjust timeout
    } else {
        // Apply retries based on the RetryConfig
        request.setReadTimeout(retryConfig.getTimeout());
        request.setRetries(retryConfig.getMaxRetries());
    }
}

}

Step 4: Test the Changes

Once the change is implemented, you will want to test that:

Retries are disabled when you set the RetryConfig with maxRetries set to 0.
Custom retry settings work as expected when a non-zero value is set for maxRetries.

public static void main(String[] args) {
FirebaseAppOptions options = new FirebaseAppOptions();

// Disable retries
RetryConfig retryConfig = new RetryConfig(0); // 0 means no retries
options.setRetryConfig(retryConfig);

FirebaseApp app = FirebaseApp.initializeApp(options);

// Now, when you call Firebase messaging, it should respect the no-retry setting

}

Summary of the Fix: Expose RetryConfig to the FirebaseAppOptions so that it can be passed when initializing FirebaseApp.Modify the newAuthorizedRequestFactory method to use the RetryConfig for controlling retries.
Allow the user to disable retries or configure custom retries based on their preferences. This approach would give users full control over the retry behavior, allowing them to handle retries themselves if needed.

SOLUTION:
I exposed a method to set RetryConfig in the FirebaseAppOptions so the user can disable retries or set custom retry limits.

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

No branches or pull requests

3 participants