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

RTP17b #835

Merged
merged 20 commits into from
May 22, 2019
Merged

RTP17b #835

merged 20 commits into from
May 22, 2019

Conversation

ricardopereira
Copy link
Contributor

@ricardopereira ricardopereira commented Mar 1, 2019

(RTP17b) The events that should be applied to the RTP17 presence map are:

  • any ENTER, PRESENT or UPDATE event with a connectionId that matches the current client’s connectionId;
  • any LEAVE event with a connectionId that matches the current client’s connectionId and is NOT a ‘synthesized leave’ (an event that has a connectionId which is not an initial substring of its id, per RTP2b1 )

Related #737

Swift Regression https://bugs.swift.org/browse/SR-2429

That's why sometimes some tests were failing because the server responded differently: X-Ably-Errorcode or X-Ably-errorcode, etc.
when channel is Suspended. Realtime sends an ATTACHED message after a successful resume.
for (ARTRealtimeChannel* channel in self.channels.nosyncIterable) {
if (channel.state_nosync == ARTRealtimeChannelSuspended) {
[channel _attach:nil];
}
Copy link
Contributor Author

@ricardopereira ricardopereira Mar 7, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did this fix in this PR because the RTP17b test was failing because of this. Discussion here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ricardopereira With this removal, does the library comply with RTN15c3? "when a resume request results in a CONNECTED with a new connectionId ... The client library should initiate an attach for channels that are in the SUSPENDED state. For all channels in the ATTACHING or ATTACHED state, the client library should fail any previously queued messages for that channel and initiate a new attach..."

cf my comment in slack "you shouldn't be sending an attached after a successful resume, only for an unsuccessful one" -- you still need to do the latter.

(From that test log it looks like the connection moved to suspended, but it's not obvious why from the log, the resume was successful so I can't see any reason for it to do so)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With this removal, does the library comply with RTN15c3?

@SimonWoolf Yes it does. When I implemented RTN15c3, I forgot to remove that bit because the new implementation already handle that case. You can see that the channel will reattach

if (![message.connectionId isEqualToString:self.connection.id_nosync]) {
[self.logger warn:@"R:%p ARTRealtime: connection has reconnected, but resume failed. Reattaching any attached channels", self];
// Reattach all channels
for (ARTRealtimeChannel *channel in self.channels.nosyncIterable) {
[channel reattachWithReason:message.error callback:nil];
}
_resuming = false;
}
and it does check the SUSPENDED channel state
case ARTRealtimeChannelSuspended:
[self.realtime.logger debug:__FILE__ line:__LINE__ message:@"R:%p C:%p (%@) attached or suspended and will reattach", _realtime, self, self.name];
break;
case ARTRealtimeChannelAttaching:
[self.realtime.logger debug:__FILE__ line:__LINE__ message:@"R:%p C:%p (%@) already attaching", _realtime, self, self.name];
if (callback) [_attachedEventEmitter once:callback];
return;
default:
break;
}
[self internalAttach:callback withReason:reason storeErrorInfo:false];

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(From that test log it looks like the connection moved to suspended, but it's not obvious why from the log, the resume was successful so I can't see any reason for it to do so)

@SimonWoolf That's because the test forces to suspend:

// Inject an additional member into the myMember set, then force a suspended state
client.simulateSuspended(beforeSuspension: { done in
channel.presenceMap.localMembers.add(additionalMember)
done()
})
expect(client.connection.state).to(equal(.suspended))

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I forgot to remove that bit because the new implementation already handle that case

👍

Though looking at reattachWithReason, it looks to me like it's reattaching channels in every state except attaching. So (1) it's starting an attach for channels in initialized, detached, or failed, which it really shouldn't be; and (2) it isn't initiating a new attach for a channel in the attaching state (we've just started a completely new connection, so any previously-in-progress attach needs to be started again). Or am I misreading it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SimonWoolf You're not misreading. It seems so, it's not respecting RTN15c3. Issue has been created: #847

@ricardopereira ricardopereira marked this pull request as ready for review March 7, 2019 17:21
Case: Push test was failing because lib was returning an error with 204 status code which shouldn't.
…gnized selector sent to instance

Because of 8fb2e0c, there are 2 ARTBaseMessage (ARTPresenceMessage) class method swizzling and Aspects doesn't support that and that's why the error occurs. There are similar issues in the Aspects repo like this one: Aspects/issues/145. I tried the fix of that PR but it didn't work. So, I decided to change all of the class methods swizzling to fix this case and reduce future issues.
Copy link
Member

@SimonWoolf SimonWoolf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The actual RTP17b bit (newer comparison etc.) looks good, but some questions re the sync() method and the channel reattaching bit

@@ -119,6 +120,10 @@ - (void)internalRemove:(ARTPresenceMessage *)message {
}

- (void)internalRemove:(ARTPresenceMessage *)message force:(BOOL)force {
if ([message.connectionId isEqualToString:self.delegate.connectionId] && !message.isSynthesized) {
[_localMembers removeObject:message];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now you've added this, you need to remove line 134, or it'll do the remove unconditionally

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed ca32ef2. Thanks

for (ARTRealtimeChannel* channel in self.channels.nosyncIterable) {
if (channel.state_nosync == ARTRealtimeChannelSuspended) {
[channel _attach:nil];
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ricardopereira With this removal, does the library comply with RTN15c3? "when a resume request results in a CONNECTED with a new connectionId ... The client library should initiate an attach for channels that are in the SUSPENDED state. For all channels in the ATTACHING or ATTACHED state, the client library should fail any previously queued messages for that channel and initiate a new attach..."

cf my comment in slack "you shouldn't be sending an attached after a successful resume, only for an unsuccessful one" -- you still need to do the latter.

(From that test log it looks like the connection moved to suspended, but it's not obvious why from the log, the resume was successful so I can't see any reason for it to do so)

if (self.presenceMap.syncMsgSerial) {
msg.channelSerial = self.presenceMap.syncChannelSerial;
msg.msgSerial = [NSNumber numberWithLongLong:self.presenceMap.syncMsgSerial];
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand this. What is a syncMsgSerial? It looks like it's being set from a SYNC msgSerial, but that isn't a thing (no incoming messages ever have msgSerials, and SYNCs don't have them in either direction). Nothing in RTP3 tells you to do this, it only asks for the channelSerial.

Also, AFAICS syncChannelSerial and syncMsgSerial are never unset in endSync, so any sync() call will result in the lib trying to resume an actually-successfully-completed sync, no?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SimonWoolf Thanks for pointing this out. Fixed dc84181.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And the second issue (second paragraph of my comment)? presenceMap.syncChannelSerial is only ever set, never unset, and you're setting it on the sync unconditionally, requesting a resume of a sync that actually completed successfully?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SimonWoolf Right, fixed 0d7cdc0. Set syncChannelSerial to nil when the sync ends.

}
}
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't see the bit of this test that tests synthesized leave's effect on the own-members set, as the test name implies? (If it is there than it's odd that it passed, since https://github.com/ably/ably-cocoa/pull/835/files#r278056029 means that the logic wasn't actually taking effect)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SimonWoolf You're right, that part is missing. What's the best way to test the synthesized leave's effect? I'm thinking in forcing a synthesized leave of one existing presence and force a sync. Then after the sync, the user should be updated since the user is re-entered and the final members map should remain the same, no leave has taken effect.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A proper end-to-end test that forces realtime to do a synthesized leave is a bit annoying if only because it means the test will take at least 15 seconds. But if you want to do that, something like: enter, force a disconnect, wait 20s, reconnect, wait to see the synthesized leave (& sync showing the member not present), wait for lib to automatically re-enter.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SimonWoolf Thanks, updated the test case 46dd5e7.

@ricardopereira
Copy link
Contributor Author

ricardopereira commented May 3, 2019

It needs #845 for the test suite pass.

Branch updated.

@ricardopereira ricardopereira requested a review from SimonWoolf May 3, 2019 07:37
@ricardopereira ricardopereira merged commit a926e4d into develop May 22, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

2 participants