Skip to content

Choosing Whether to Enable Retries in Firebase App Options #1075

Open

Description

@ksiisk99

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.

Activity

  1. google-oss-bot commented on Feb 12, 2025

    @google-oss-bot

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

  2. Mohima6 commented on Mar 21, 2025

    @Mohima6

    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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions