-
Notifications
You must be signed in to change notification settings - Fork 617
Migrate some executors in fad/in-app-feedback #4350
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
Conversation
Generated by 🚫 Danger |
Coverage Report 1Affected Products
Test Logs |
@@ -65,7 +65,7 @@ class FirebaseAppDistributionImpl implements FirebaseAppDistribution { | |||
private final SignInStorage signInStorage; | |||
private final ReleaseIdentifier releaseIdentifier; | |||
private final ScreenshotTaker screenshotTaker; | |||
private final Executor taskExecutor; | |||
private final Executor blockingExecutor; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Requires blocking executor here because some of the uses may wait on a lock via synchronized blocks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@vkryachko Some of the uses in this file do not block at all. Would you recommend that we also inject the Lightweight executor, or is it up to us if we're OK using the Blocking executor for lighter weight tasks?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
may wait on a lock via synchronized blocks
Do any of these blocks do network or disk IO synchronously or call task.get()
? or are they all in memory operations?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(optional)
Additionally, speaking of synchronized blocks in the context of tasks and executors, consider refactoring to something like the following go/android-concurrent/whichexecutor#sequentialexecutor, where code that needs synchronization could run on the sequential "decorator", and code that does not can run on the executor directly.
The caveat is that we can't use ListenableFutures as described in the doc above and have to use Tasks instead. see TaskCompletionSource on how to do it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've also noticed that for some continuations in this file you are not passing in the executor, i.e. onSuccessTask
, continueWithTask
etc. This results in the continuations to run on the main thread, is that intentional?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do any of these blocks do network or disk IO synchronously or call task.get()? or are they all in memory operations?
Actually looking closer
.signInTester()
accesses SharedPreferences, which I understand could in theory touch disk.
Disk it touched only when the SharedPreferences object is constructed, and for any synchronous writes like commit, so those operations should use the @Background
executor as using an unbounded pool(i.e. @Blocking
) for disk io puts a lot of pressure on the file system.
Besides that the other potential blocking calls should all be in memory. They involve synchronized blocks (like this one), which in theory shouldn't block for long if at all, but could block briefly depending on various race conditions.
In this case it's best to use a blocking executor since it's unbounded in the number of threads which avoids dead locks, but it's better to refactor to a sequential as mentioned below.
I assume logging using
android.util.Log
does not block but maybe that's wishful thinking...
It's safe to log and it does not block.
Additionally, speaking of synchronized blocks in the context of tasks and executors, consider refactoring to something like the following go/android-concurrent/whichexecutor#sequentialexecutor
That looks great, we'll look into that. It doesn't feel great having synchronized blocks all over the place right now.
I've also noticed that for some continuations in this file you are not passing in the executor, i.e. onSuccessTask, continueWithTask etc. This results in the continuations to run on the main thread, is that intentional?
I see a couple of them are accidental, actually. I'll fix those. Others though are intentional, if not ideal. We run a lot of Task handlers on the main thread if they should execute quickly. But that's mostly for convenience, rather than create an executor to run something that should return immediately. Maybe in this new world of explicit shared executors we should use
@Lightweight
for these.
In my opinion this is a bad default that Tasks provide(even though at the time it was a reasonable thing to do), the general android guidance is to run as little code on the UI thread as possible, i.e. only things that must
run there, like UI related code. Given this default, I agree that using executors explicitly in all continuations is a better approach and we should even add a linter warning for calls without an executor(maybe?).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK thanks Vlad, in summary we will:
- Move construction of SharedPreferences or synchronous writes to a
@Background
executor - Avoid using synchronized blocks in favor of sequential executors or other approaches (already removed some in Remove some synchronized blocks from FirebaseAppDistributionImpl #4353)
- Use explicit executors for Task handlers throughout instead of defaulting to UI thread
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks Lee,
Move construction of SharedPreferences or synchronous writes to a
@Background
executor
One thing I'll add: it would be awesome if you could implement this as a self-contained class that just does the right thing, that way we would be able to put it in say firebase-common, register it as a component, and have all teams benefit from it. wdyt?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As for the UI thread, looks like all sdks use it a lot :( #4363
So it could be a follow up effort once the executor migration is done
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good. I'm going to make each of these changes in followup PRs.
Size Report 1Affected Products
Test Logs |
FirebaseApp firebaseApp, FirebaseAppDistributionLifecycleNotifier lifecycleNotifier) { | ||
this(firebaseApp, lifecycleNotifier, Executors.newSingleThreadExecutor()); | ||
} | ||
private final Executor backgroundExecutor; | ||
|
||
@VisibleForTesting |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove this annotation - this constructor is now called from FirebaseAppDistributionRegistrar
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah good catch
48d57ce
to
c9cf94d
Compare
e77f3c8
to
233dead
Compare
c9cf94d
to
fe558c7
Compare
233dead
to
6323c25
Compare
03b7b9e
to
d545fc8
Compare
fe558c7
to
ec07e81
Compare
Startup Time Report 1Note: Layout is sometimes suboptimal due to limited formatting support on GitHub. Please check this report on GCS. Startup time comparison between the CI merge commit (8110244) and the base commit (56e2e2d) are not available. No macrobenchmark data found for the base commit (56e2e2d). Analysis for the CI merge commit (8110244) can be found at: |
* Migrate executors in fad/in-app-feedback * Add an import and format
No description provided.