Skip to content

FirebaseMessaging sendEachAsync(), sendEachForMulticastAsync() can cause thread deadlock #981

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

Closed
jhkim-grip opened this issue Aug 23, 2024 · 2 comments · Fixed by #985
Closed
Assignees

Comments

@jhkim-grip
Copy link

jhkim-grip commented Aug 23, 2024

[REQUIRED] Step 2: Describe your environment

  • Operating System version: Java 11
  • Firebase SDK version: 9.2.0
  • Library version:
  • Firebase Product: Firebase cloud messaging (FCM)

[REQUIRED] Step 3: Describe the problem

Steps to reproduce:

We use custom thread pool due to OOM problem of default thread manager that sdk used.

private ExecutorService createThreadPoolExecutor() {
		final int corePoolSize = 50; 
		final int maximumPoolSize = 50; 
		final long keepAliveTime = 60L;
		final TimeUnit unit = TimeUnit.SECONDS;
		final BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(500);

		return new ThreadPoolExecutor(
				corePoolSize,
				maximumPoolSize,
				keepAliveTime,
				unit,
				workQueue,
				new ThreadPoolExecutor.CallerRunsPolicy()
		);
	}

FirebaseOptions.Builder().setCredentials(GoogleCredentials.fromStream(serviceAccount))
					.setThreadManager(fcmThreadManager)
					.build();

but in FirebaseMessaging sendEachOpAsync(), sendEachForMulticastAsync()
both parent method itself use thread pool by callAsync() and inside there is child method sendOpForSendResponse() that actually call the fcm send api also use the same thread pool by callAsync()

스크린샷 2024-08-23 오후 2 25 18 스크린샷 2024-08-23 오후 2 25 46

the problem is thread pool can be full of parent method and then it will be forever wait status cause there is no actual message sending thread.

it did not reproduce heavily we have 15 pods and only 1 pod have problem.
we get thread dump from that pod and we get all 50 thread wait in same line where parent thread that wait all the child thread to end.

at java.util.concurrent.locks.LockSupport.park([email protected]/Unknown Source)
	at com.google.common.util.concurrent.AbstractFuture.get(AbstractFuture.java:502)
	at com.google.common.util.concurrent.AbstractFuture$TrustedFuture.get(AbstractFuture.java:83)
        at com.google.common.util.concurrent.ForwardingFuture.get(ForwardingFuture.java:62)
	at com.google.firebase.messaging.FirebaseMessaging$2.execute(FirebaseMessaging.java:231)

Relevant Code:

i think thread code of above will be enough.
we just have thread pool setting code and FirebaseMessaging call code.

@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.

@jonathanedey
Copy link
Contributor

Thank you @jhkim-grip for spotting this!

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