Skip to content
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

Prevent Bugsnag.init from instantiating more than one client #403

Merged
merged 6 commits into from
Jan 4, 2019

Conversation

fractalwrench
Copy link
Contributor

Goal

If Bugsnag.init is called multiple times, multiple Client objects will be instantiated. This is generally not the desired behaviour, could lead to undesired side-effects, and is also a very expensive operation (approx 100ms for each initialisation on a test device).

For a real world example, if Bugsnag.init is called from within onCreate in an Activity rather than an Application subclass, it's possible that multiple clients could be instantiated over the app's lifecycle.

This changeset alters Bugsnag.init so that it will only instantiate a Client if one hasn't been created already. For exceptional cases where a user needs to instantiate multiple Client objects, it remains possible to do so by invoking the Client constructor directly.

Changeset

  • Synchronized initialisation code within the Bugsnag.init methods, so that only one thread can attempt initialisation at a time.
  • Only created a new Client object if the existing field is null, and otherwise return the existing instance.
  • Log a warning if the existing client field is not null, as this most likely indicates the integration is not following our latest recommendations.

Tests

  • Ran the example app with two Bugsnag.init calls, and verified that a warning was logged.
  • Created a mazerunner test which repeatedly invokes all method variants of Bugsnag.init on multiple threads, and verifies only one client was created.

@fractalwrench fractalwrench changed the title Prevent Bugsnag.init instantiating more than one client Prevent Bugsnag.init from instantiating more than one client Dec 20, 2018
}

val futures = threadPool.invokeAll(callables)
val uniqueClients = futures.map { it.get() }.distinct()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This blocks until all the Callables have finished execution, then gets the returned Client objects and removes any duplicates from the Collection (there should only ever be 1 item in this list).

@fractalwrench
Copy link
Contributor Author

I've addressed all outstanding feedback and have reduced duplication in the init methods.

Copy link
Contributor

@bengourley bengourley left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

Tested manually and I see the log message when multiple init() calls are made. Error reporting still works.

@fractalwrench fractalwrench merged commit db5646c into master Jan 4, 2019
@fractalwrench fractalwrench deleted the init-safety branch January 4, 2019 10:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants