-
Notifications
You must be signed in to change notification settings - Fork 46
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
Adding disk buffering, part 3 #194
Adding disk buffering, part 3 #194
Conversation
...va/io/opentelemetry/android/features/diskbuffering/scheduler/DefaultExportScheduleHandler.kt
Outdated
Show resolved
Hide resolved
...src/main/java/io/opentelemetry/android/internal/services/periodicwork/PeriodicWorkService.kt
Outdated
Show resolved
Hide resolved
/** | ||
* Sets up a scheduling mechanism to read and export previously stored signals in disk. | ||
*/ | ||
interface ExportScheduleHandler { |
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.
Not for this PR:
If using the Kotlin explicitApi
mode, all those interfaces have to be made public
, then you can use the org.jetbrains.kotlinx.binary-compatibility-validator
plugin to generate a public API file its quite nice.
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.
That sounds really nice 👍 I think we should create an issue to address it later.
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.
@marandaneto do you mind creating an issue for this? I'm not familiar with it and would love to see an example in action. Thanks!
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.
Sure, #217
It's quite simple, the plugin does all the magic, all you need to do is install the plugin and make the commands part of the CI pipeline, so the CI generates the API dump in every CI run if any, the check is already done automatically part of the builtin gradle check
.
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.
noice!
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.
There do appear to be a lot of moving parts here...There's a PeriodicWorkService
that delegates to the WorkDelegator
that, when run, delegates all of its enqueued items to be run later in its ExecutorService
and also tells a Handler
to post a callback run on the MainLooper
, which will repeat the process (every 10 seconds).
There's also this PeriodicRunnable
which is a Runnable
that when run()
s checks to see if enough time has passed and yes then it actually runs via the onRun()
template method, but it always reenqueues itself back into the PeriodicWorkService
global service instance, which it finds though the global ServiceManager
instance.
Phew. That's a lot to keep track of for something that we just want to run every 10 seconds.
Oh yeah, and I haven't even mentioned yet that there's the DefaultExportScheduler
which is an implementation of PeriodicRunnable
.
There's something that's eating at me about the period in the PeriodicRunnable
and the scheduled time in the PeriodicWorkService
and how they might be at odds with each other. If you have a PeriodicRunnable
that wants to be run every second, but the PeriodicWorkService
only can schedule work every 10 seconds, then doesn't that effectively make the PeriodicRunnable
period 10 seconds as well? In other words, maybe it can only run as fast as its service?
In any case, there is probably something in the merits of using the Handler
/Looper
mechanism that I need to read up on...but I wonder why we can't just use a plain old ScheduledExecutorService
for all of this?
...rc/main/java/io/opentelemetry/android/features/diskbuffering/DiskBufferingConfiguration.java
Show resolved
Hide resolved
instrumentation/src/main/java/io/opentelemetry/android/internal/tools/time/SystemTime.kt
Show resolved
Hide resolved
instrumentation/src/main/java/io/opentelemetry/android/internal/tools/time/SystemTime.kt
Show resolved
Hide resolved
@breedx-splk regarding:
Yeah it's a lot 😅 - I'll try to go over them one by one in here.
Correct, the The
This is related to not abusing of Android app's resources, I believe that whatever work is done by this lib will always be secondary in terms of the host app's priorities, so from a user's perspective, having a lot of secondary background work happening at any time, probably continuously running doesn't seem like a behavior I'd like to get in my app from one of its libs, so that's why I believe there should be a small window of time where it does all it needs to do in the background and then waits for another window. It's common to have some kind of minimum delay between background jobs in Android due to proper resource consumption, like in WorkManager for example. 10 seconds doesn't mean anything special to me though, if we think we need shorter delays I think we can reduce that number.
This one's a utility for background tasks that need to happen more than once. But if a task only needs to happen once it can just implement Runnable directly and get enqueued once in the
Yeah the
Yes, we can lower that number, although I think we should also be cautious about how often we need to do work in the background for the reasons I mentioned earlier.
I think we could also use I think it all can be summarized to trying to make this lib a good android lib citizen 😅 - there might be cases where we need to do more work or take more resources but I'd like to keep those as exceptions and try to do most of this lib's work by using as little as possible. |
Thanks for the depth of response and taking the time to write it. Oh that's a good point about the I do wonder, when it comes to reducing resource usage, if having a recurring task firing when there may not be work to be done is a good idea. In any case, I don't think any of this is a showstopper. Thanks for putting in all this work. I'll do another pass through and see if I have anything specific, but I remember it looks good overall. |
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.
Progress! Looking forward to seeing it all come together in the final episode. :)
override fun enable() { | ||
if (!enabled.getAndSet(true)) { | ||
ServiceManager.get().getService(PeriodicWorkService::class.java) | ||
.enqueue(DefaultExportScheduler()) |
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.
Can we make the DefaultExportScheduler
an instance field passed thru constructor? Both good DI practice and saves object creation.
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.
You're right, that sounds way better! I'll add the changes.
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, it's updated now.
/** | ||
* Sets up a scheduling mechanism to read and export previously stored signals in disk. | ||
*/ | ||
interface ExportScheduleHandler { |
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.
@marandaneto do you mind creating an issue for this? I'm not familiar with it and would love to see an example in action. Thanks!
Good point 😅 it sounds like a good topic for the SIG 👍 |
I think any tool that prevents creating more than one thread for now should work yeah, I'm not sure if that's the case even for |
It should take just one more PR after this one!
This PR is for setting the scaffolding that will allow to periodically read and export previously stored data from the disk. This is needed because the previous PRs related to disk buffering have taken care of the writing part only, so now we're going to set up the reading part which has to happen periodically (and in a background thread) to make sure new data is exported at some point.
Goals for these changes
For the next part
Which seems like it will be the last one, we should take care of: