typelevel / cats-effect

The pure asynchronous runtime for Scala
https://typelevel.org/cats-effect/
Apache License 2.0
2k stars 515 forks source link

functions used by the CE scalaJS version of the scheduler realTime values are flaky in recent versions of Chrome #3295

Closed sbuzzard closed 1 year ago

sbuzzard commented 1 year ago

In recent versions of Chrome (not sure how far back but definitely 107.0.5304.121 on Mac), the functions used here SchedulerCompanionPlatform - specifically, the performance.pointOrigin + performance.now calls - return stale times under certain circumstances. It seems to be the time when it was first called by an app, until you restart the browser.

Since the CE scheduler on scalajs is used by IOFiber to implement Clock[IO].realTime, this resulted in our application getting back a time in the past when calling Clock[IO].realTime, the specific time dependent on when the browser was last restarted. I haven't looked yet into whether this is a known issue in Chrome or what CE specifically can do about it (other than not use them). In an attempt to minimize the problem, I took the nowMicrosImpl chunk of code from the link above and ran in our app to verify that was the issue.

armanbilge commented 1 year ago

It seems to be the time when it was first called by an app, until you restart the browser.

This is what the value of performance.timeOrigin generally is. So if that's the value you are getting, it suggests that performance.now() is returning 0, would you be able to check that?

Also, how long before you observe this behavior?

matthughes commented 1 year ago
Cursor_and_DevTools_-_github_com_typelevel_cats-effect_issues_3295

This was taken when system clock is Wed Nov 30 2:00 PM EST.

armanbilge commented 1 year ago

I see, thanks, that's helpful 🤔

matthughes commented 1 year ago

It is possible that putting your laptop to sleep causes this. With newly opened browser (not just tab, but quit and reopen browser)

new Date().valueOf() - (window.performance.timeOrigin + window.performance.now())

would be very close to zero. I then put my laptop to sleep and upon waking, I now see much higher numbers.

https://stackoverflow.com/questions/73778224/performance-timeorigin-returning-a-date-in-the-past seems relevant.

matthughes commented 1 year ago

And the Chromium bug: https://bugs.chromium.org/p/chromium/issues/detail?id=1365808&q=timeOrigin&can=2

matthughes commented 1 year ago

Looks like they are going to revert the change but it hasn't hit Chrome release train yet.

matthughes commented 1 year ago

Is there a way we could write a unit test in CE to verify the system is behaving as expected? Are the CE tests run just on node or also in a browser?

armanbilge commented 1 year ago

There is a test for it here. https://github.com/typelevel/cats-effect/blob/4eba1a7317ef36d48727f9d9168cc6ecf1c78920/tests/js/src/test/scala/cats/effect/unsafe/SchedulerSpec.scala#L39-L44

It's one of a handful of specs we run on browsers. https://github.com/typelevel/cats-effect/blob/4eba1a7317ef36d48727f9d9168cc6ecf1c78920/project/CI.scala#L78-L109

matthughes commented 1 year ago

Very cool. Would be neat to run in Chrome too but I doubt it would catch anything.

What is the benefit of using the performance API vs Date.now()?

armanbilge commented 1 year ago

It runs in both Chrome and Firefox, you might need to scroll the code box :)

I made the changes in https://github.com/typelevel/cats-effect/pull/2895 so we can have high-precision time. In retrospect I am not sure if it was worth it, at least in browsers.

sbuzzard commented 1 year ago

Thanks for looking at, Arman. Matt beat me to it with the chrome issue data. Solution is to never put your laptop to sleep. Tim Cook would give the thumbs up to that I'm sure.

armanbilge commented 1 year ago

Aha, it looks like the property we are relying on is actually part of the specification.

https://w3c.github.io/hr-time/#timeorigin-attribute

In fact, they even have an interactive test suite you can run in your browser which includes a test "Window timeOrigin is close to Date.now() when there is no system clock adjustment."

https://wpt.live/hr-time/timeOrigin.html

When I navigate to that page in Chrome it is failing that test. When I navigate to the same page in Firefox it is passing.

So I think it's fair to say this is a Chrome issue.

armanbilge commented 1 year ago

Chrome 109 was released which fixes this bug.

https://chromereleases.googleblog.com/2023/01/stable-channel-update-for-desktop.html