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

Fetch and execute recipes once every 24 hours if no restart #588

Closed
Osmose opened this issue Mar 7, 2017 · 10 comments
Closed

Fetch and execute recipes once every 24 hours if no restart #588

Osmose opened this issue Mar 7, 2017 · 10 comments
Assignees

Comments

@Osmose
Copy link
Contributor

Osmose commented Mar 7, 2017

We should be running recipes once every 24 hours for users who haven't restarted the browser in that time. Executing recipes should reset the time, so that a user with the browser open for an entire week should fetch and execute new recipes 7 times (unless their computer is asleep or some other state that stops Firefox from running; we should default to whatever behavior the updater uses in that case).

@mythmon mythmon self-assigned this Mar 24, 2017
@mythmon mythmon added this to the Sprint 8 - March 20th to April 1st milestone Mar 24, 2017
@mythmon
Copy link
Contributor

mythmon commented Mar 24, 2017

I propose that we use this opportunity to decouple our execution from the browser start. Instead I suggest that we keep a record of the last time we have run. If it has been more than 24 hours since the last run, run again. We would check at browser start up, and then again periodically. In pseudo code:

on browser start, and every 30 minutes
    if last_run is more than 24 hours ago
        run()
        last_run = now

@Osmose @gregglind @MattGrimes What do you think about this?

@gregglind
Copy link
Contributor

gregglind commented Mar 24, 2017 via email

@mythmon
Copy link
Contributor

mythmon commented Mar 24, 2017

Perhaps obvious, but I would prefer a system that is robust to client clock.

This technique assumes that the client's clock is at least monotonic and increasing at about 1 second per second. We don't have any way to check the time more than that in a way that I'm happy with, for now. We'll use UTC to deal with time zones. The timestamps we use to test filter expressions come from the server, but that particular query happens to be one of the most expensive ones we have, so we definitely can't increase its load by 50x overnight.

Every startup (NECESARY TO handles experiment tagging for ongoing At least once per day for ongoing sessions.

I can't parse this paragraph. Did something go wrong with a copy/paste?

Derail: Is there some etag/caching magic to allow more often than once per day cheaply?

We already cache things pretty heavily, so there isn't much of an easy solution here. We are looking at some more things to potentially improve performance in the future (mostly things that require the system add-on to be finished). Once we have this interval system in the wild, we can definitely experiment with running more than once a day.

@Osmose
Copy link
Contributor Author

Osmose commented Mar 24, 2017

I propose that we use this opportunity to decouple our execution from the browser start. Instead I suggest that we keep a record of the last time we have run. If it has been more than 24 hours since the last run, run again. We would check at browser start up, and then again periodically.

What are the benefits of making this change?

This technique assumes that the client's clock is at least monotonic and increasing at about 1 second per second. We don't have any way to check the time more than that in a way that I'm happy with, for now. We'll use UTC to deal with time zones. The timestamps we use to test filter expressions come from the server, but that particular query happens to be one of the most expensive ones we have, so we definitely can't increase its load by 50x overnight.

I've been told by several different people over the years that client clocks are broken in very odd ways for many users. Does the app updater, for example, rely on the client clock, or does it get around this issue somehow?

If we can't get confirmation that other high-priority update mechanisms consider the client clock reliable, I don't think it's wise for us to make this assumption.

Every startup (NECESARY TO handles experiment tagging for ongoing At least once per day for ongoing sessions.

I can't parse this paragraph. Did something go wrong with a copy/paste?

I believe Gregg is pointing out that he thinks we need to execute recipes on startup to make sure we tag in-progress experiments in Telemetry, as the Telemetry API for marking a user as active in an experiment doesn't retain state between sessions and needs to be called on startup.

But, I think we're okay here, because the add-on will be keeping tracking of this without needing to run recipes. On startup, the add-on will, independently of running recipes, inform Telemetry of active experiments, and then the next time we execute recipes, will inform Telemetry if any of the experiments were deactivated.

@mythmon
Copy link
Contributor

mythmon commented Mar 24, 2017

What are the benefits of making this change?

Client start up is unpredictable and out of our control. It means we have a different patterns of execution for the "every 24 hours" case and the startup case. The execution model I've proposed here should be more predictable and means we only have one way of triggering execution, instead of several.

If we can't get confirmation that other high-priority update mechanisms consider the client clock reliable, I don't think it's wise for us to make this assumption.

I claim that add-on manager (at least) considers the clock to be reliable enough for updates.

Tracing that maze of fun times leads me to believe that the add-on manager, via the UpdateManagerTimer, trusts the system clock at least enough to do things about every 86400 seconds.

@mythmon
Copy link
Contributor

mythmon commented Mar 24, 2017

PS: I used the add-on manager as an example because it is the one I was able to find code for, with @rhelmer's help. I haven't found out how the many app updater works yet.

@Osmose
Copy link
Contributor Author

Osmose commented Mar 25, 2017

Tracing that maze of fun times leads me to believe that the add-on manager, via the UpdateManagerTimer, trusts the system clock at least enough to do things about every 86400 seconds.

Sounds good to me!

@rhelmer
Copy link
Contributor

rhelmer commented Mar 25, 2017

@Osmose lulz. This is why we also set timers to run shortly after startup such as https://dxr.mozilla.org/mozilla-central/rev/e03e0c60462c775c7558a1dc9d5cf2076c3cd1f9/toolkit/mozapps/extensions/internal/XPIProvider.jsm#2946-2950

The problem for hot-reloadable code like add-ons is that there isn't a great way to unregister right now - I filed https://bugzilla.mozilla.org/show_bug.cgi?id=1350471 for that.

There is also a simple Timer module that implements set{Interval,Timeout} and also clear{Interval,Timeout} in https://dxr.mozilla.org/mozilla-central/rev/e03e0c60462c775c7558a1dc9d5cf2076c3cd1f9/toolkit/modules/Timer.jsm which is built on nsITimer.

The advantage to the former is that it has some safeguards and does extra work for you like persisting the timer across sessions.

@rhelmer
Copy link
Contributor

rhelmer commented Mar 26, 2017

BTW I put up a patch on bug 1350471 - assuming I can land and uplift that in short order, you'd be able to set a timer like:

let SO_MANY_SECONDS = 1234;
let timerManager = Cc["@mozilla.org/updates/timer-manager;1"].
                   getService(Ci.nsIUpdateTimerManager);
timerManager.registerTimer("my-special-timer", () => {
  this.doVerySpecialThings();
}, SO_MANY_SECONDS);

You can also lazy-load the service if you want, with XPCOMUtils.defineLazyServiceGetter.

When your add-on is shutdown or disabled, you can unregister it (you can either get the service again or keep the timerManager reference, either way):

timerManager.unregisterTimer("my-special-timer");

Then if the user shuts down before SO_MANY_SECONDS, the timer will continue where it left off when Firefox starts up again.

@rhelmer
Copy link
Contributor

rhelmer commented Mar 26, 2017

Sorry I didn't really address the main point @Osmose was making above - we do need to trust the system clock, to a point. It doesn't matter if the date is wrong or the time is slow/fast, but we do expect that the time overall goes forward.

As mentioned above, the nsIUpdateTimerManager stores the last update time (in a pref like app.update.lastUpdateTime.${timerID}), so it isn't simply reset from 0 when Firefox is restarted.

I think it's true that if a user's clock is wildly fluctuating or keeps resetting to an old date etc. then it's certainly possible this won't work as expected, but they probably have other problems if this is happening.

@Osmose Osmose modified the milestones: Sprint 8 - March 20th to April 1st, Sprint 9 - April 3rd, 2017 to April 15th, 2017 Apr 3, 2017
@mythmon mythmon modified the milestones: Sprint 9 - April 3rd, 2017 to April 14th, 2017, preference-experiments Jan 30, 2018
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

No branches or pull requests

4 participants