Bug 185575

Summary: Overly aggressive timer throttling in service workers
Product: WebKit Reporter: Zach Bjornson <zbbjornson>
Component: Service WorkersAssignee: Chris Dumez <cdumez>
Status: RESOLVED FIXED    
Severity: Normal CC: beidson, cdumez, commit-queue, ggaren, webkit-bug-importer, youennf
Priority: P2 Keywords: InRadar
Version: Safari Technology Preview   
Hardware: Mac   
OS: macOS 10.13   
Bug Depends on:    
Bug Blocks: 185626    
Attachments:
Description Flags
Patch
none
Patch none

Description Zach Bjornson 2018-05-11 19:35:37 PDT
Safari seems to throttle timers extremely aggressively in service workers. If I run this code:

    let previous = Date.now();
    const interval = 1000;
    setInterval(() => {
        const now = Date.now();
        const separation = now - previous;
        previous = now;
        console.log("tick", separation);
    }, interval);

most ticks run after [interval + 10,000 ms] -- e.g. 1000 ms runs at 11,000 ms and 100 ms runs at 10,100 ms. Sometimes they run closer to the actual [interval], when the main page is doing work. Disabling "DOM Timer Throttling" and "Hidden Page Timer Throttling" has no effect.

The same code in the main browser thread runs when expected (just after [interval]). Edge, Firefox and Chrome run the timers when expected in service workers.

This is a problem for our application because we use timers to batch multiple HTTP requests into fewer HTTP requests. Consequently, our batched HTTP requests are delayed up to 10 seconds.

(Safari v 11.1 / 13605.1.33.1.4)
Comment 1 Chris Dumez 2018-05-14 09:05:26 PDT
Probably our timer throttling code that kicks in because the service worker does not have any visible page.
Comment 2 Radar WebKit Bug Importer 2018-05-14 09:05:53 PDT
<rdar://problem/40219038>
Comment 3 Radar WebKit Bug Importer 2018-05-14 09:05:53 PDT
<rdar://problem/40219039>
Comment 4 Chris Dumez 2018-05-14 12:41:12 PDT
Do you have a test page? I have trouble reproducing. I see there interval very very close to 1000:
CONSOLE MESSAGE: line 14: 1004
CONSOLE MESSAGE: line 14: 1000
CONSOLE MESSAGE: line 14: 1002
CONSOLE MESSAGE: line 14: 1003
CONSOLE MESSAGE: line 14: 1000
CONSOLE MESSAGE: line 14: 1006
Comment 5 Chris Dumez 2018-05-14 12:45:33 PDT
I suspect this could be throttling outside WebKit known as AppNap. If I look at Activity Monitor, I see that the service worker process gets App Napped after ~30 seconds, I believe this impacts our timers as well. I'll look into preventing App Nap.
Comment 6 Chris Dumez 2018-05-14 12:53:52 PDT
(In reply to Chris Dumez from comment #5)
> I suspect this could be throttling outside WebKit known as AppNap. If I look
> at Activity Monitor, I see that the service worker process gets App Napped
> after ~30 seconds, I believe this impacts our timers as well. I'll look into
> preventing App Nap.

To confirm that this is the issue you are experiencing, you can disable App Nap via:
defaults write NSGlobalDomain NSAppSleepDisabled -bool YES
Comment 7 Chris Dumez 2018-05-14 14:09:16 PDT
Created attachment 340355 [details]
Patch
Comment 8 Geoffrey Garen 2018-05-14 14:19:07 PDT
Comment on attachment 340355 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=340355&action=review

> Source/WebKit/UIProcess/ServiceWorkerProcessProxy.cpp:113
> +    // Prevent App Nap for Service Worker processes.
> +    setProcessSuppressionEnabled(false);

I think we want a FIXME with a link to a bugzilla bug that says Service Workers should nap if all their clients are napping. It's not a high priority bug, but it's good to clarify that's the design that we think would be best.
Comment 9 Chris Dumez 2018-05-14 14:27:42 PDT
Created attachment 340359 [details]
Patch
Comment 10 WebKit Commit Bot 2018-05-14 15:31:47 PDT
Comment on attachment 340359 [details]
Patch

Clearing flags on attachment: 340359

Committed r231771: <https://trac.webkit.org/changeset/231771>
Comment 11 WebKit Commit Bot 2018-05-14 15:31:49 PDT
All reviewed patches have been landed.  Closing bug.
Comment 12 Zach Bjornson 2018-05-14 20:18:40 PDT
Thanks for the fast fix! `NSGlobalDomain NSAppSleepDisabled -bool YES` fixes the issue, so I assume the patch works as well.
Comment 13 Chris Dumez 2018-05-15 08:45:30 PDT
(In reply to Zach Bjornson from comment #12)
> Thanks for the fast fix! `NSGlobalDomain NSAppSleepDisabled -bool YES` fixes
> the issue, so I assume the patch works as well.

If you'd like, you can verify my fix by resetting this defaults and try this build:
https://s3-us-west-2.amazonaws.com/minified-archives.webkit.org/mac-highsierra-x86_64-release/231772.zip which contains my fix.

It'd be useful to make sure everything behaves as expected now.