-
-
Notifications
You must be signed in to change notification settings - Fork 654
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
Presence heartbeat (v2) #3727
Presence heartbeat (v2) #3727
Conversation
e590d66
to
0d14548
Compare
The linter failure in the previous CI failure has been addressed by linter pragmata for now. (I thought I'd used that construct previously; but no, that was inside a The current CI failure is due to a tests-only auxiliary file being (not unreasonably) mistaken for an actual test file by Jest, because it's in a subdirectory of the |
(Addendum: I haven't simply done that because, on reflection, the additional tests they're in support of may be more code than is worth having around. I'd prefer a second opinion on that.) |
I'm not sure I can speak to the necessity of those tests, but maybe for the Jest failure -- it's a bit of a patch, but perhaps the code in Some brief research hasn't revealed any recommendations from Jest on where to put such things. |
It probably should be, though: there are other timer-dependent tests (see: They may also want to make use of interval trees – in which case I'll have to properly separate out... well, a lot of things – but even then the interval-tree library wrapper should probably be a sub-library, just for the sake of separation of concerns. (If I just wanted to silence the Jest failure, I could put a dummy test in that file.) |
Pinging @gnprice. |
Marking priority, following the issue. |
Thanks again @ray-kraesig for these changes! Now that the key parts of #3886 are in, want to rebase this to take advantage of Lolex being in master? (And the remaining commits of #3886 should be landing shortly, too, but I think those won't interact with this branch.) I think the now-merged commits from #3886 also resolve the Jest file-layout questions discussed above. But please mention if I've missed something and that's not the case. I'm also about to go read through this code -- I'll just skip over for now the bits that look like they were covered by #3886. |
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.
And read through the first half of this! Namely these commits, corresponding to what was in #3704:
37c5bb7 api [nfc]: rename reportPresence
parameter
e12c452 presence: strip throttling from reportPresence
wrapper
a32a1ac presence: add Heartbeat class (+ tests)
987a9b7 presence: move all presence-reporting logic into new HeartbeatComponent
f17b7d6 heartbeat: convert tests to use Lolex
e0a265d heartbeat: change presence-reporting protocol
3ca8fe1 heartbeat [nfc]: remove state
parameter from callback
Thanks for the revisions! I like the changes. This looks close; there are a couple of things below.
I haven't yet read in detail the subsequent changes:
0d590a5 heartbeat [nfc]: add fine-grained event tracking to tests
5491e5e heartbeat [nfc]: extend heartbeat-test event system
d612271 deps: add interval-set library
27aa07c heartbeat: define additional constraints
0d14548 heartbeat tests: add app-suspension test cases
I think it might be simplest to reserve those for a subsequent PR.
One small commit-level remark: the summary line "heartbeat: define additional constraints" sounds to me like it's going to change something in the code's behavior. (There are a lot of things "constraints" could mean.) It turns out it doesn't, adding only a comment and some tests, and it'd be great to communicate that in the summary line. Perhaps s/define/Document, and test,/?
const now = new Date(); | ||
if (differenceInSeconds(now, lastReportPresence) < 60) { | ||
// TODO throttle properly; probably fold setInterval logic in here |
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.
Commit-level comments on this commit:
e12c452 presence: strip throttling from reportPresence
wrapper
Nit: "would fix #3699 as literally reported" is no longer quite right, as we've edited #3699 so it describes the problem more broadly.
Related nit: "would fix #..." is a dangerous phrase to put in a commit message, because GitHub sees the "fix" and doesn't understand the "would". :-) Should basically always get reworded to hide from GitHub's auto-close rules, with e.g. a circumlocution like "would be a fix for #...".
Stepping back, though, I think my comment on this commit from the previous PR still applies:
#3704 (review)
This looks like a good implementation of what it says on the tin. I think it may not be part of what we want following today's discussion, though.
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.
Stepping back, though, I think my comment on this commit from the previous PR still applies:
#3704 (review)This looks like a good implementation of what it says on the tin. I think it may not be part of what we want following today's discussion, though.
The fix for this is basically to squash the second commit into the fourth commit. As there's not much substance to it, done. (Although this does make the commit message uncomfortably crowded. 😕)
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.
I like the result, thanks!
The commit message does get a bit longer. I think it might actually on net be simpler than before, though. One way it's certainly simpler is that the "If the user logs in and out" bullet previously had to tell a multi-step story ("This was previously concealed by ... which was itself removed in a previous patch") and that's now a simple before/after.
AppState.addEventListener('change', this.updateHeartbeatState); | ||
} | ||
|
||
componentWillUnmount() { | ||
AppState.removeEventListener('change', this.updateHeartbeatState); |
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.
We had a comment thread on this bit over on the previous PR: #3704 (comment)
Your explanation there makes sense to me! I'm convinced.
I also wanted to mention that thread here because you'd said:
(On the other hand, I'd argue that the lone existing use of
.isActive
, over insrc/events/eventMiddleware.js
, is a bug! Or at least is closely involved in one. But that's not directly relevant here; I'll elaborate somewhere else.)
and I don't want that thought to get lost. 🙂 Want to elaborate on that -- perhaps in a new issue, or a chat thread?
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.
Eh, I might as well express my current thoughts on that in the form of commit messages.
Opened PR #3936.
src/presence/PresenceHeartbeat.js
Outdated
// Note that "PureComponent" is of questionable veracity: this component's | ||
// entire purpose is to emit network calls for their observable side effects | ||
// as a side effect of being rendered. | ||
// | ||
// However, it is at least true that there is never a need to call `render()` | ||
// (and therefore `componentDidUpdate()`) if the props haven't changed. | ||
class PresenceHeartbeat extends PureComponent<Props> { |
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.
On the previous PR we discussed a previous version of this comment: #3704 (comment) Thanks for the updates!
I think it's pretty reasonable to say that the term "pure" here is confusing and of questionable veracity.
I think what my thought here boils down to now is that that complaint is really all about the naming of PureComponent
. What we're doing is 100% consistent with the expectations of a React PureComponent
, which are documented here -- it's just that those expectations don't include all the things that you might (reasonably!) expect the word "pure" to mean, or to be true of "a pure component".
A comment about that mismatch of PureComponent
vs. the meaning of "pure" in general would be fine to have here. (Certainly it wouldn't be the first comment in our codebase that complains about a design choice that happened somewhere else 😉 -- I've written plenty of those.) What I don't want is a warning that we're hacking around or breaking some API expectation that potentially could expose us to problems when the React implementation changes, in a spot where in fact we aren't.
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.
What I don't want is a warning that we're hacking around or breaking some API expectation that potentially could expose us to problems when the React implementation changes, in a spot where in fact we aren't.
Ah, I see the ambiguity now. Amended significantly.
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.
New version looks great!
e373c09
to
190bc38
Compare
190bc38
to
6600f12
Compare
Fair enough! Snipped for now. |
Thanks @ray-kraesig for the revisions! One question and a nit, both in the commit messages.
Seems to me like it actually fixes #3699. Is there a particular aspect of that that's still open that you have in mind? Maybe this is a sign that my revised title was too vague 🙂 : "Presence-reporting logic is confused, in overlapping ways". I think the bar for closing the issue isn't that we become sure there are no bugs or confusions in the new version -- just that it's no longer confused in the ways we knew about. And of course a related good thing to achieve (as this PR does) is that it's written in a way that we can hope is less prone to confusion. 😉
s/channel/stream/ :smile: Oh, and I guess a second nit: s/heartbeat/presence/ in that summary line would feel a bit more on-point to me. I think it's because this change is mainly aimed at the server-facing reporting of presence, rather than the internal implementation choices (even though it involves making changes to the latter to accomplish its changes to the former.) |
6600f12
to
3675c24
Compare
As of that commit, yes: |
Ah, got it. Thanks! I'll merge shortly. I think I'll make one small further edit to the commit messages: on this "Fixes (the original version of) #3699" commit, I'll add a mention that a fix to the remainder of that issue is coming up next. Reduces the suspense a bit for the reader. 😉 |
Mobile apps are not usually described as "having focus", and the underlying parameter value is `"active"` anyway.
Add `Heartbeat`, a generic-looking class which will be used to perform presence-reporting. Also add tests, to ensure that it behaves as expected.
Replace the existing presence-reporting logic with HeartbeatComponent, instantiated as part of a new zero-display React component located under AppEventHandlers. In particular, strip the throttling logic from `reportPresence`. This fixes at least three issues: * If the user logged in and out, or otherwise performed an additional "initial fetch" without killing the app, the presence timer would be started multiple times. (The negative effects of this were previously concealed by the throttling logic.) * `idle` events were not treated differently from `active` events by the throttling logic, and would almost invariably be swallowed. * If the user went idle (e.g. by hitting the Home button), the presence timer would still run, and would still attempt to send `active` notifications. (These attempts were often suppressed while the app was in the background, but this was never guaranteed.) Fixes the original version of zulip#3699; the next commit will complete the fix for that issue. This is also work towards zulip#3659. Unfortunately, there is no user-visible change yet: modifications will be needed on the Zulip server side as well.
Following discussion on chat.zulip.org's #mobile-team stream [0], adjust the presence-reporting protocol so that it never sends "idle". Fixes zulip#3699. [0] https://chat.zulip.org/#narrow/stream/243-mobile-team/topic/presence.20and.20notifications/near/800081
The heartbeat callback is now only ever called with `true`. Simplify the associated code by removing the now-constant argument.
3675c24
to
9e3d52d
Compare
Rewrite, and possibly unnecessarily thoroughly test, the presence-heartbeat code.
Resumption of PR #3704.
Fixes #3699.