Code Monkey home page Code Monkey logo

background-sync's Introduction

Background Synchronization

Specifications for one-time and periodic ServiceWorker-based background synchronization and explainer documents to describe the motivation and usage for this feature.

background-sync's People

Contributors

addyosmani avatar annevk avatar asankah avatar autokagami avatar clelland avatar cwilso avatar forsakenharmony avatar jakearchibald avatar jkarlin avatar johnmellor avatar jungkees avatar jyasskin avatar kenjibaheux avatar markdalgleish avatar maxbarrett avatar mikaello avatar miketaylr avatar mkruisselbrink avatar mugdhalakhani avatar nsatragno avatar rayankans avatar sideshowbarker avatar slightlyoff avatar talater avatar travisleithead avatar wibblymat avatar yoavweiss avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

background-sync's Issues

Battery draining

As with location tracking, this seems like a reason why the user has to opt in. E.g. if a user opts into the Notification API that site can then cause a bunch of notifications to appear, perhaps leading the user to disable the feature.

User agents could also have heuristics here and perhaps indicate in the browser/OS settings what sites are draining the battery.

Location tracking

Per use-cases.md this is an issue.

I guess the rationale behind this being a concern is that the assumption is that a service worker implementation does not upgrade in the background, but only when a site is actually visited (or just prior, given "good" heuristics).

This seems like something the UX should make clear to the user when opting into this feature. I don't think there's anything we can do beyond that, right?

Do we need minDelay & maxDelay?

What are their use-cases?

minDelay - for periodic syncs I think the minPeriod would be the min delay. Is there a case you'd want them to be different?

maxDelay - given #35 (comment), I don't think we'd want to allow this.

Minimal API surface needed to start solving one-off sync use cases?

Could we try to scope and design the API in a way that let us solve a good chunk of the use cases without precluding the resolution of the remaining use cases (i.e. Minimal Viable Product)?

The one-off sync use cases seems simpler than the periodic sync use cases which should make them easier to design for.

What would be the minimal viable surface we need to solve a good chunk of the one-off sync use cases as explained in https://github.com/slightlyoff/BackgroundSync/blob/master/use-cases.md ?

Behavior on desktop platforms

For Windows / OSX / Linux: Should background sync events start the browser if it isn't running? I've added text in 9feda0d which says no because the user can leave the browser running if they like.

For mobile platforms it should wake up the browser as the browser is likely to be closed due to memory pressure.

Thoughts?

Should the ID be auto-generated by default?

@annevk @clelland @jakearchibald

As of ccdb392 the id can be default set by the UA. After some thought, I don't like the idea of a default id.

  1. What are the use cases for a default id? I can only think of calendar events, and we're not (currently) supporting exact timers anyway. And even for a calendar, you could compose an id based on the name and time of the event. This would also help to prevent duplicate registrations.

  2. Default id makes it easy to accidentally double register. Imagine the page registers a repeating sync each time it's opened. If it had to use the same id each time the registration would reject.

Remove "notify when next online" use cases

We've discussed three potential use cases for sync over time:

  1. periodic synchronization (content refresh, log uploading, etc.)
  2. large uploads/downloads (sync media up or down)
  3. online notification (send emails/tweets)

I think 2 is clearly out of scope as serviceworkers kills scripts after 30 seconds. We'll need a new solution (my vote is to add a background option to Fetch).

I also think that we should consider 3 out of scope. We shouldn't conflate the idea of a background sync with what is essentially navigator.online. We should solve 3 by bringing navigator.online to ServiceWorkers.

Thoughts?

API for "If I request this, will the user be asked?"

Maybe not so applicable to bsync, but this is likely to become a pattern for future permissions so…

If I know the UA will ask the user for permission, I'd like to show a button for the user to press that gives them full context for its use. Eg "Enhance results by location", which will ask the user for geo permissions. However, if the UA isn't going to ask the user for permission, I won't show the button & just go ahead and do it.

I guess this could take the form of a boolean, or an option to the requesting function that prevents it asking the user.

hasPermission() implies boolean

I think we should just go with permission() similar to the Notifications API. (The reason it cannot be a property is because we want the result to be asynchronous and the result can change over time.)

Should SyncRegistrationOptions.data be more than a DOMString?

Since this is a JavaScript API, should clients be allowed so store arbitrary JavaScript objects in the data field of a SyncRegistrationOptions object?

Certainly it needs to be serializable, since this data will have to outlive the process which registers it, so we can't support storing open file handles or message ports, for instance. It seems like anything which is JSON-serializable should be allowed, and ideally the API could support anything which could also be serialized by, say, IndexedDB.

Should we extend this to allow more than a single string?

Two permissions, two APIs

It seems like one-shots and periodic ought to have separate permissions at the API level (the UA can merge them or do whatever it will behind the scenes). In which case, we should probably have two API functions. Which means we need names. I proposing, register(id, options) and registerPeriodic(id, minPeriod, options). Any reason not to make the options the same for both?

Then we also need ways to check on those permissions. We could rely on the web permissions API for that but we don't want to delay others browsers from implementing sync by having to first implement web permissions. So should there be two hasPermission() calls as well? E.g., hasPermission() and hasPeriodicPermission() or should hasPermission() just return both values?

provide strategy for handling partial syncs

How should the UA and content handle partial syncs due to being terminated before they complete? For example, if the sync'ing content process is killed due to memory pressure.

One approach would be for the sync content script to post a "sync complete" back to the UA. If the UA notices the sync process terminates before getting that notification it could relaunch it sooner than it normally would.

It seems this might be error prone, though, as content could easily forget to post the "sync complete". Any other ideas for handling this condition gracefully?

Remove IDL from explainer

Explainer documents should lead with problems and examples, not IDL. If you're debating IDL, please do it in a spec or in a separate IDL/TypeScript file.

Alarm API

The use cases document mentions this.

There is http://www.w3.org/TR/2013/WD-web-alarms-20130205/ (latest version link is broken) written by @cdumez.

The web obviously needs something like this so we can have https://clock.org/ and https://calendar.org/ and https://reminders.org/ all be applications that have the same capabilities as native.

The question is however whether background synchronization is the right place to address this. Or whether that should be a similar API but with a distinct opt in.

Do we want to put a data cap on sync request storage?

The browser will have to persistently hold onto the sync request data and id string. Do we want to allow arbitrary size of this data or cap it per request or SW? What would a reasonable cap be? We can probably keep it quite small and encourage use of IndexedDB for anything large.

Transfer priority of sync requests

Are sync requests always lower transfer priority than resource requests coming from the document?

To make things concrete, I'll conjure up a reader example like Pocket. It might bulk sync a bunch of articles for reading later. But if you open one up immediately in the document, it should load at an interactive priority. It's easy to see the difference in priorities there. Now, let's say you want to share the article via a social network. If there's no connectivity, it could use a background sync with 'urgent' set to true to share the article. When connectivity returns and the user starts accessing other articles, what's the priority relationship here? Should the sync request be issued to the network with the same priority as everything else?

Actually, perhaps I misunderstand. The 'urgent' attribute only controls when the sync event is fired, but not the transfer priority of the actual fetch() call. I guess the UA's network stack could contextually assume that fetches issued within a sync event should have lower transfer priority. But maybe the fetch() API should just be explicit about it.

Hm, I need to think more about it. I'm curious what others think about my rambling comments.

What should promises resolve with?

syncManager.register and syncManager.unregister currently return promises resolving to booleans. There's no mention in the spec of what these booleans mean. I don't think they should refer to success/failure -- the promise's fate already covers that.

Should we change that to something like

  Promise<SyncRegistrationOptions> register(DOMString id, optional SyncRegistrationOptions options);
  Promise<void> unregister(DOMString id);

And register can return the options that were actually stored (in case they were modified by the user agent.) Or just have both return void promises?

Resolving a duplicate registration

Follow-up on a sidenote in #41

Emphasis added:

Default id makes it easy to accidentally double register. Imagine the page registers a repeating sync
each time it's opened. If it had to use the same id each time the registration would reject.

I'm not sure this has to be the case. A nice design touch of the ServiceWorker API is that it lets you call register without having to worry about duplicate registrations. It resolves straight with the existing registration if any or gives you a new one otherwise (primary key being [sw script, scope])

Can we also follow this pattern in BG sync?

<!DOCTYPE html>
<!-- https://tweet.example.com/index.html -->
<html>
  <head>
    <script>
      navigator.serviceWorker.register("/sw.js");

      // Registering for sync will fail unless a viable SW is available, so wait
      // for that to happen.
      navigator.serviceWorker.ready.then(function(swRegistration) {
        // Returns a Promise
        swRegistration.syncManager.register(
          {
            id: "update"
          })
        .then(function() { // Success (new registration or existing registration)
               },
               function() { // Failure
                 // User/UA denied permission
               });
      });
    </script>
  </head>
  <body> ... </body>
</html>

instead of

<!DOCTYPE html>
<!-- https://tweet.example.com/index.html -->
<html>
  <head>
    <script>
      navigator.serviceWorker.register("/sw.js");

      // Registering for sync will fail unless a viable SW is available, so wait
      // for that to happen.
      navigator.serviceWorker.ready.then(function(swRegistration) {

      // checking if we have to register our update sync
      var updateSyncNotRegistered = true;
      if (swRegistration.syncManager.getRegistrations().then((regs) => {
           for(reg in regs) {
                if(reg.id == "update") {
                      updateSyncNotRegistered = false;
                      break;
                }
           }
      });

      if (updateSyncNotRegistered) {
        // Returns a Promise
        swRegistration.syncManager.register(
          {
            id: "update"
          })
        .then(function() { // Success
               },
               function() { // Failure
                 // User/UA denied permission
                 // but not because of duplicate registration since we checked for that
               });
        });
    }
    </script>
  </head>
  <body> ... </body>
</html>

I imagine that we should also allow a mere call to register with the same id to overwrite a previously registered sync request.

function setupUpdates(userPrefs) {
   // [...] (getting hold of swRegistration, etc.)
   swRegistration.syncManager.register(
          {
            id: "update",
            //...
            allowOnBattery: userPref["allowOnBattery"],
            //...
          })
         .then(function() { // Success (new registration or updated existing registration
               },
               function() { // Failure
                 // User/UA denied permission
               });
      );
}

//...
   // code where handling changes to user preferences is handled
   // ...
  setupUpdates(userPrefs);
  // ...

Instead of having to:

  • look up for the existing registration if any
  • unregistering
  • and then registering

Does this make sense? Or did I miss something?

Uploading either needs a new function or a new home

We have two primary use cases for SW sync. Below are the cases and their needs from an API:

  1. Periodic updating of content so that the next time the user sees the page it has somewhat fresh data to look at while loading the page.
    1. Failure is okay, the page won't be fresh. No need to try again in the near future.
    2. The event might need to be repeating, but generally infrequent.
    3. Synchronizing might be complex, providing an imperative sync event liberates the developer.
  2. Uploading data when next online (e.g., tweets, emails, preference changes).
    1. Failure is not okay, that message must be sent! Must have a try-again mechanism.
    2. No need to repeat.
    3. It's reasonable to have a declarative API here. "Please complete this PUT request and keep trying until it's finished".

I think that these are substantially different enough that they at least need to be separated into two functions, and possibly different modules. The first use case needs an event (onsync) scheduled by the UA. The second might just be some sort of persistent fetch SW provides.

description seems insecure

There's no way we know whether or not the description is legitimate or something used to trick the user into getting tracked.

I think I raised that point before, but I cannot find a reference.

Add getRegistration(DOMString id) to SyncManager

In order to unregister a registration you first need to get a hold of the SyncRegistration object. To do that you have to call registrations() and then search the returned list. It seems like we should provide a getRegistration(DOMString id) in SyncManager as well.

More opportunities for BG sync to outperform self-made solutions (e.g. robustness of onsync)

Here is one thing that came out while talking to folks interested in this API.

Ignoring BG sync's ability to outrun the life of the web app, these folks had implemented something similar to "background sync".

When offline, they let their users perform some basic operations in their web app (e.g. delete an item). Ideally, when the user comes back online these operations are synchronized with the server.

In practice, they apply an exponential backoff to the synchronization operation. This helps them deal with various conditions: from offline (despite say navigator.online being true) to kind of online and up to server issues (e.g. 500).

Are there opportunities for bg sync to do a better job here?

  1. take care of the exponential backoff strategy => I think this is already on the map since it's mentioned in the explainer.
  2. have onsync be a more robust signal that the user is truly back online with optionally some extra guarantees about the quality of the connection (e.g. not "kind of online") and the reachability of specific endpoints. This seems quite desirable given that it could make bg sync even more power friendly.

Perhaps, a lot of that might simply be UA optimizations. Then, depending on what we learn, we might want to look into offering more flexibility in v2.

Thoughts?

Units for interval

The explainer example includes an interval property:

interval: 1000 * 60 * 60 * 24,  // ms, default: heuristic

Specifying intervals in milliseconds is quite fiddly (not to mention unnatural, since intervals that short wouldn't be allowed by most UAs anyway).

Consider instead passing in an explicit unit, e.g. in the style of both Moment.js Durations and datejs .add:

interval: { hours: 12 }

or possibly as a string:

interval: "12h"

(seconds, minutes, hours, days and years all have unique starting letters; months unfortunately overlap with minutes)

It would of course be sensible to align this with any future plans for representing time intervals in ECMAScript.

Guarding data posts against closing the tab

Consider this:

addToOutbox(importantEmail);

fetch(url, {
  method: 'POST',
  body: importantEmail
}).then(response => {
  if (!response.ok) throw Error(response.statusText);
  removeFromOutbox(importantEmail);
  showSuccessUI();
}).catch(function() {
  return navigator.serviceWorker.ready.then(reg => {
    return reg.sync.register({tag: 'outbox'});
  });
});

If sending an email fails, we request a sync and handle it later. However, if the tab/browser closes before the request completes, or the page navigates away, the request fails but we never get the chance to send that request.

Data isn't lost, but we can't send that email in the background. It becomes more attractive to do this:

addToOutbox(importantEmail);

navigator.serviceWorker.ready.then(reg => {
  return reg.sync.register({tag: 'outbox'})
});

fetch(url, {
  method: 'POST',
  body: importantEmail
}).then(response => {
  if (!response.ok) throw Error(response.statusText);
  removeFromOutbox(importantEmail);
  showSuccessUI();

  if (outboxEmpty) {
    navigator.serviceWorker.ready.then(reg => {
      return reg.sync.getRegistration('outbox');
    }).then(syncReg => syncReg.unregister());
  }
});

As in, we schedule a sync with every important POST, and unregister it if it succeeds. I'm worried there may be a race here where the sync event fires file the fetch is still being attempted, resulting in a double fetch.

I could schedule a sync event and do all of my outbox emptying there (not from the page at all), but I have no guarantee that it'll happen immediately, and communicating success/failure back to the page is a bit of a postMessage mess.

Is there anything we can do to improve this? Should we?

Couple of half-baked ideas:

reg.sync.register({
  tag: 'outbox',
  onlySyncIfThisPromiseFailsToFulfill: fetch(url, {
    method: 'POST',
    body: importantEmail
  }).then(response => {
    if (!response.ok) throw Error(response.statusText);
  })
});

Or:

reg.sync.register({
  tag: 'outbox',
  onlySyncIfNoPagesAreOpen: true
});

…which would prevent race conditions with the page.

Expose registration options?

Currently you cannot inspect the registration. So in your code you need to keep track of what options belong to what ID. Oftentimes I think we reach the conclusion that we would like to be able to inspect those values which would argue for a slightly different design here.

E.g. we could introduce a SyncRegistration object that you construct with an ID and options and you would register that object (and getRegistrations would return copies of them).

Critical battery condition: leave it up to the user agent.

Some native platform block (native) background sync operations when the device is operating under critical battery conditions.

The spec might want to note that the user agent has the freedom to do so (e.g. "the user agent may ignore pending bg sync requests if the device is operating under critical battery conditions").

Query and Removal Methods

As requestSync() might create a prompt in some UAs, it'd be good there were a query mechanism (hasSync(id)?) that allowed a developer to test for existence of a sync request without creating any prompts. Similarly, it should be possible to remove sync requests programmatically.

Firing onsync and register/unregister

If register or unregister is called in onsync on the firing sync's id, what is the effect on the backoff mechanism?

Scenario 1: During onsync, the id is unregistered but waitUntil rejects. Do we try again later with the backoff mechanism or stop?

Scenario 2: During onsync, the id is overwritten but waitUntil rejects. Do we try again later with the backoff mechanism or stop? If we try again later, do we try again with the original registration's parameters or the new one's?

Simpler sync? Fire every 2 hours.

What if we removed the suggestedInterval and simply fired onsync every X hours where X is a known value to the web developer? The event would have useful attributes like "is online, is on battery or plugged in, network type". Then the SW could decide to sync now or wait for a later time.

Advantages include simple event coalescing, simple implementation, and more predictable behavior for the web developer.

The primary disadvantage is that onsync is likely to be fired more often than necessary, causing unnecessary memory pressure and resource waste. More refined implementations could reduce the resource waste and memory pressure, but that removes the 'simple implementation' advantage.

Use Push and a Background Fetch/XHR instead of background sync

Given our use cases: periodic refresh, background upload/download of messages and bulk data, we might be better served by breaking the cases apart into the following:

  1. Periodic refresh (twitter, mail, news articles): Use the push API like native apps already do today.

  2. Retry upload of message when next online: SW.fetch (or perhaps XHR) with background capability that fires a SW event (or writes to indexedDB?) when done.

Background fetch would support resumable downloads immediately and resumable uploads would come in the future as we made progress on that.

What does network-any mean?

I can see two possible interpretations of minRequiredNetwork: "network-any", and I think that either of them is redundant.

  1. network-any means "Any network state" -- this is supported by its position in the enum, but I think it's identical to network-offline (Unless there's a state with even less than offline-access -- maybe network-card-ripped-out-and-dangling-from-the-cable?)
  2. network-any means "Some (any) network is available" -- this would be identical to network-online, as far as I can tell.

Is there another distinction that I'm just not seeing right now, or should one of these be removed from the IDL?

Guidance on background sync and shared workers

Andrew Overholt of Mozilla suggested I post here about use cases that come up in the context of Firefox OS and service workers that want to do background sync. It may help with the use case document.

Context

The email app on Firefox OS. It wants to do background syncs every so often when there is connectivity available. The user indicates a rough time interval (5 mins, 10 minutes, 15 minutes, 30 minutes, 1 hour). The sync interval does not have to be exact, just approximate to those intervals, and only if there is connectivity available.

Background sync is used instead of something like a push API-backed server because it is a generic email application that can connect to IMAP/ActiveSync/POP3 servers that likely do not have support for push.

Firefox OS apps can have multiple browser windows opened per app, so the email app would want to use a shared worker to do the network and IndexedDB work for syncing and for handling serving slices of the email data to the browser windows. We just what one entity responsible for the network connections and data services, and holding the business logic related to the data models.

Issue

This gets a bit tricky though when considering a service worker with a background sync entry point:

  • The sync could come in and there could be no open email windows, so the shared worker may not be spun up yet.
  • Or, the background sync could come in while there is an open email window, and the shared worker is available.

However, service workers spinning up shared workers did not seem to be allowed, if I read the old issues list for service workers correctly.

So guidance on this use case is appreciated. Here are some things that were discussed when talking about the issue within our group:

Possibilities

Talk to shared worker: Maybe there is a way for the background sync entry point to communicate to the shared worker, and start up the shared worker if not running, and wait for it to complete its network and database work before signaling the sync is complete.

However, it is my understanding that this is not allowed in a service worker at the moment.

Service worker as the backend: Use the service worker as the shared worker, so embedding the code for the sync work in the service workers, and the user visible browser windows for the app would talk to it for the data slices.

However, we do not want to burden the service worker with more work, where it might interfere or slow down the service worker handling its basic fetch duties. Plus, the service worker seemed volatile, and not really designed to be more long-lived for use by user visible browser windows for business logic/data services for the UI.

openWindow: Perhaps the service worker could use openWindow to open a non-visible browser window that would then talk to/spin up the shared worker.

However, it is unclear if those windows would be user visible or not. In this case we would not want that window visible as it is just a pipeline to spin up the shared worker, and that window needs to be destroyed at some point. It seems like a better expression of intention to just spin up the shared worker directly, as something that is not visible and just related to data processing.

Match the sync API with the more established Push API

We should follow in the footsteps of Push and move navigator.sync to serviceworker.syncManager. Here is some proposed IDL:

partial interface ServiceWorkerRegistration {
    readonly attribute SyncManager syncManager;
};

interface SyncManager {
    Promise register(string id, optional SyncRegistrationOptions);
    Promise<bool> unregister(string id);
    Promise<vector<string>> getRegistrations();
    Promise<SyncPermissionStatus> hasPermission ();
};

interface SyncRegistrationOptions {
    attribute int minInterval;
    attribute bool repeating;
    attribute string data;  // bytes instead?
    attribute string description;
    attribute string lang;
    attribute string dir;
};

partial interface ServiceWorkerGlobalScope {
                attribute EventHandler onsync;
};

Thoughts?

Advice for developers

We should maybe add some advice.

There's many apps on my phone that have background updates. When I open the app I see something interesting which within seconds is replaced by "newer" content and I can no longer find what I was looking at. This is rather annoying behavior.

Should sync event target a specific server?

Considering that most use cases will want to communicate with a specific server once they become online, should SyncRegistrationOptions also allow the user to specify a server to ensure connectivity to that specific target?

API fit: podcatcher

I would like to better understand how this API would help some use cases, or failing that, understand what API or combination thereof would do so.

Updating podcast episodes on a daily basis but only if on Wi-Fi

The use case: Virtucon made an awesome offline-first podcatcher which leverage Push messages to efficiently grab new podcast episodes [R 1] but only if the device is on Wi-Fi [R 2]. It then shows notifications when a new episodes is ready for consumption.

Requirement R 1

Virtucon's servers would send a Push message whenever a new episode is found for a given user.

Upon receiving a Push message, the web app would register a non-recurring onSync "grabPodcast" event for the relevant podcast at an opportunistic time (determined from an empirical model of the "on Wi-Fi" condition, see below).

Requirement R2

Ideally, the web app would build and maintain a usage model to keep track of when the user's device is most likely to be on Wi-Fi.

With the API in the explainer, the web app would have to over register an onSync event to build such a model.

Perhaps something like:

  1. the web app would start by registering a recurring and relatively high frequency (e.g. every 2 hours) onSync "buildUsageModel" event
  2. on an onSync "buildUsageModel" event the web app would use the Net Info API to check if the device is on WiFi and record the outcome in a "usage model" database.
  3. if the "usage model" database contains enough data (e.g. ~2 weeks), the web app might want to reduce the frequency of this "buildUsageModel" onSync event.

Note that this is probably the best case scenario (the worst case scenario would be a polling approach: polling for new episodes from the clients and polling for Wi-Fi on a relatively high frequency basis).

Question

  1. Given the use case, should the Background Sync API take into consideration R2?

USVString instead of DOMString for id

I know this has come up somewhere before, but now that I'm implementing, having a non-utf8 compliant string is painful as I need to store the id to disk and potentially may want to sync across devices in the future. Can we switch to USVString?

A small vocabulary for data transfer

Several observers have noted that different "use cases" want very different behavior from the system -- an email app versus a movie player, for example. This diversity of needs might be easier to discuss if we had a small vocabulary for discussing it. For example:

  • structured records (emails, contacts) vs blobs (video)
  • "small" vs "large" relative to cellular bandwidth and device storage
  • user prioritized (a message fired with "Send" or "Send when online")

Should minAllowablePeriod be an async request?

Currently in the IDL, SyncManager.minAllowablePeriod is just an exposed constant.

Are there any conceivable situations where this could be dynamic, or take longer than a couple of ms to return a value? If so, then maybe we should make it an async call, something like

Promise<unsigned long> minAllowablePeriod

and it can be a promise -- for now, one that immediately resolves with the right value, but potentially slower in the future.

(I don't think that we should -- I think that, even if it could take a while to return, it will only be used by apps on startup, never in a loop, and making it async just complicates their startup logic. However, if we're ever going to want to make it async, then we should do it now)

Is 'urgent' necessary?

The use case for 'urgent' is to send an email or tweet as soon as the UA is able to. When that is will depend on the platform (e.g., iOS multitasking is constrained). Does setting a small suggestedInterval suggest the same thing? Is urgent redundant?

API fit: morning dose of news

I would like to better understand how this API would help some use cases, or failing that, understand what API or combination thereof would do so.

Morning dose of news for your commute

The use case: The Daily Planet made an awesome offline-first web app that grabs news articles and photos every morning [R 1] while its readers are asleep. What's more it's smart enough to only download high res photos if the device is on Wi-Fi [R 2] and plugged-in [R 3].

Requirement R 1 ("every morning")

With the API in the explainer, the web app would have to do a somewhat convoluted dance:

  1. first time around the web app would have to calculate how long until say 4AM and register for a non-recurring onSync "initialNewsGrab" (string id) event
  2. on an onSync "initialNewsGrab" or "regularNewsGrab" event the web app would grab the news
  3. on an onSync "initialNewsGrab" event the web app would also have to register for a recurring onSync "regularNewsGrab" event with a daily frequency

Requirement R 2 ("high res photos only on Wi-Fi")

AFAICT, the Background Sync API doesn't address this use case so the web app would have to:

  1. in the onSync event handler, the web app would use the NetInfo API to check if the device is on WiFi and determine which assets it should download.

Requirement R 3 ("high res photos only when plugged-in")

I'm not aware of any API that would help here (the System Information API was abandoned).

Questions

  1. Given the use case, should the Background Sync API take into consideration R1?
  2. For that particular use case, the solution for R2 seems OK but I have another use case for which it might be sub-optimal (will file a separate issue).
  3. Anyone aware of a solution or effort for R3?

Rename allowOnBattery to chargingOnly?

Or something else that gives us a falsey default.

I'm guessing something like chargingOnly was avoided because of devices that don't have a battery? I guess something like powerConnectedOnly avoids that.

"interval" sounds too definite

The explainer example includes an interval property:

interval: 1000 * 60 * 60 * 24,  // ms, default: heuristic

The naming of this property, and the fact that its value is in precise milliseconds, suggests:

  1. that the UA is likely to use an interval similar to that provided (with only minor tweaks for batching tasks together)
  2. that small intervals are likely to be allowed

Both of these intuitions would be incorrect, as to minimize battery/data usage, the UA is allowed to aggressively increase the intervals (e.g. to wait until the device is plugged in or on WiFi).

A more accurate name might be "minInterval", as the UA will generally avoid firing sync more frequently than the page requested, but will commonly fire sync much less frequently than the page requested.

If minInterval is also considered confusing, some other possible names include:

  • maxFrequency
  • suggestedInterval
  • preferredInterval

As for the millisecond accuracy, see issue #3 for a possible solution.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.