firebase / firebase-admin-java

Firebase Admin Java SDK
https://firebase.google.com/docs/admin/setup
Apache License 2.0
525 stars 254 forks source link

Is sendEachForMulticast thread safe #950

Open Laith-jalal opened 1 month ago

Laith-jalal commented 1 month ago

I was going through the sendEachForMulticast logic and didn't find anything to tell if it's thread safe or not, my current implementation is by calling the following in a new thread

FirebaseMessaging.getInstance().sendEachForMulticast(message)

Am I messing something here ? is my implementation thread safe ?

google-oss-bot commented 1 month ago

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

emindeniz99 commented 1 month ago

The method should not have any thread issue, because to achieve high notification throughput, we need to call the method in multiple thread.

In production, we are using the predecessor "sendmulticast" method with 6+ thread to achieve 80k+ rpm on one java process. And we didn't face with any thread safety issue.

meor9zcu12 commented 1 month ago

When using FCM admin SDK v9.3.0 sendEach api with 20 threads, 500 tokens per thread, we encountered OutOfMemoryError,

Caused by: java.lang.OutOfMemoryError: unable to create native thread: possibly out of memory or process/resource limits reached at java.base/java.lang.Thread.start0(Native Method) at java.base/java.lang.Thread.start(Thread.java:809) at java.base/java.util.concurrent.ThreadPoolExecutor.addWorker(ThreadPoolExecutor.java:945) at java.base/java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1364) at com.google.common.util.concurrent.MoreExecutors$ListeningDecorator.execute(MoreExecutors.java:640) at java.base/java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:145) at com.google.common.util.concurrent.AbstractListeningExecutorService.submit(AbstractListeningExecutorService.java:79) at com.google.firebase.FirebaseApp.submit(FirebaseApp.java:384) at com.google.firebase.ImplFirebaseTrampolines.submitCallable(ImplFirebaseTrampolines.java:98) at com.google.firebase.internal.CallableOperation.callAsync(CallableOperation.java:47) at com.google.firebase.messaging.FirebaseMessaging$2.execute(FirebaseMessaging.java:227) at com.google.firebase.messaging.FirebaseMessaging$2.execute(FirebaseMessaging.java:222) at com.google.firebase.internal.CallableOperation.call(CallableOperation.java:36) at com.google.firebase.messaging.FirebaseMessaging.sendEach(FirebaseMessaging.java:189)

emindeniz99 commented 1 month ago

When using FCM admin SDK v9.3.0 sendEach api with 20 threads, 500 tokens per thread, we encountered OutOfMemoryError,

Caused by: java.lang.OutOfMemoryError: unable to create native thread: possibly out of memory or process/resource limits reached at java.base/java.lang.Thread.start0(Native Method) at java.base/java.lang.Thread.start(Thread.java:809) at java.base/java.util.concurrent.ThreadPoolExecutor.addWorker(ThreadPoolExecutor.java:945) at java.base/java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1364) at com.google.common.util.concurrent.MoreExecutors$ListeningDecorator.execute(MoreExecutors.java:640) at java.base/java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:145) at com.google.common.util.concurrent.AbstractListeningExecutorService.submit(AbstractListeningExecutorService.java:79) at com.google.firebase.FirebaseApp.submit(FirebaseApp.java:384) at com.google.firebase.ImplFirebaseTrampolines.submitCallable(ImplFirebaseTrampolines.java:98) at com.google.firebase.internal.CallableOperation.callAsync(CallableOperation.java:47) at com.google.firebase.messaging.FirebaseMessaging$2.execute(FirebaseMessaging.java:227) at com.google.firebase.messaging.FirebaseMessaging$2.execute(FirebaseMessaging.java:222) at com.google.firebase.internal.CallableOperation.call(CallableOperation.java:36) at com.google.firebase.messaging.FirebaseMessaging.sendEach(FirebaseMessaging.java:189)

It is normal :). sendEachForMulticast has performance issues. The method creates a thread and opens a connection per device token. You can use old API until 20 June or try to limit concurrency or device token count. Concurrent sending requests should not be high, depending on your hardware, RAM and network socket limits. You can check the issue. https://github.com/firebase/firebase-admin-java/issues/834#issuecomment-1890969169