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

Replaced spawn of multiple queues in subscriptions for a single queue… #28

Merged
merged 9 commits into from
Sep 11, 2018
Merged

Replaced spawn of multiple queues in subscriptions for a single queue… #28

merged 9 commits into from
Sep 11, 2018

Conversation

MarioBajr
Copy link
Contributor

Currently batch subscriptions spawn multiple background queues, and apart from the running subscription request, all others sit in the wait state, consuming unnecessary resources and affecting requests from other AWSAppSyncClient instances.
Also for every subscription request, AppSyncMQTTClient disconnects all previously connected sockets and connects to the new endpoints, consuming unnecessary resources in case of a batch subscription request.

Description of changes:

  • Replaced usage of shared SubscriptionsOrderHelper to coordinate sequencial subscription requests with a single queue owned by AWSAppSyncClient
  • Added a small cancellable delay in MQTTClient to avoid sequential disconnections and reconnections of the socket while subscribing to multiple topics.

@rohandubal
Copy link
Contributor

Thanks for the PR @MarioBajr ! I am looking into this and will reply back.

Copy link
Contributor

@rohandubal rohandubal left a comment

Choose a reason for hiding this comment

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

Thanks again for the PR! The changes look good to me. I will do some testing on my side to validate some real-world scenarios and will approve once I am done validating those.

@MarioBajr
Copy link
Contributor Author

Awesome, thank you too.

self.subscriptionsQueue.async { [weak self] in
let semaphore = DispatchSemaphore(value: 0)

self?.performSubscriptionRequest(completionHandler: { (success, error) in
Copy link

@fans3210 fans3210 Jun 28, 2018

Choose a reason for hiding this comment

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

I applied this pr in my personal repo and it improved a lot. only small question about the weak self. Tested and found that I have to manually keep a strong reference of the watcher otherwise the performSubscriptionRequest method won't be called because self is nil and the semaphore will wait forever which will affect all other subscriptions. That is what I found, not sure whether I'm using it correctly,

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You're absolutely right, it should bail out on self = nil before acquiring the semaphore. Will submit a fix. The behaviour of not performing the subscription if the watcher gets dealloc is correct though. You should retain the watcher if you have interest in the subscription, releasing it to unsubscribe as you can see in the deinit.

@rohandubal
Copy link
Contributor

Hello @MarioBajr

Could you please rebase the changes before I could merge them?

Thanks,
Rohan

Mario Araujo added 4 commits June 29, 2018 11:11
… provided by AppSyncClient. Added a small cancellable delay in MQTTClient to avoid sequential disconnections and reconnections socket requests while subscribing to multiple topics.
…acquiring the semaphore while starting the subscription.
… init and removing the requirement of retaining subscriptionQueue

- Guaranteeing management of all AppSyncMQTTClient ivars in the same internal background queue.
@MarioBajr
Copy link
Contributor Author

Done 👍

@rohandubal
Copy link
Contributor

Great! Will merge this soon 😄

…TTClient

- Fixed AppSyncMQTTClient holding MQTTSubscritionWatcher strongly
- Added unit tests to AppSyncMQTTClient
- Configured travis to run unit tests
@mutablealligator
Copy link

@MarioBajr Sorry for the delayed response. Can you resolve the conflicts and update the PR?

@MarioBajr
Copy link
Contributor Author

MarioBajr commented Sep 7, 2018

Hi @kvasukib, sorry for the delay, was on holidays :)
While working on this merge, noticed that a new bug will be introduced in this PR because of a new behaviour added in AWSIoTMQTTClient. This PR adds a delay on all MQTTClient connections in AppSyncMQTTClient, then it's possible to have a watcher being deallocated before any attempt to connect. The problem is that AWSAppSyncSubscriptionWatcher tries to unsubscribe on deinit, triggering the new exception Cannot call unsubscribe before connecting to the server inside unsubscribeTopic:ackCallback: because _userDidIssueConnectis FALSE. Will work to solve this issue soon.

- Fixed AppSyncMQTTClient merge error
- Fixed AppSyncMQTTClient calling unsubscribe on AWSIoTMQTTClient in unstable states
- Disabled AWSAppSyncTests because it requires some work to be able to run within a CI
@MarioBajr
Copy link
Contributor Author

Done, had to skip AWSAppSyncTests.swift from running in travis because it requires some configuration. About these tests, it behaves as integration tests, having mixed feelings if it should be in this SDK. I would replace them by unit tests with responses coming from a mocked networkTransport.

@rohandubal
Copy link
Contributor

rohandubal commented Sep 10, 2018

@MarioBajr I was trying to integrate these changes, but I am running into issues while testing on my side. Whenever I have more than 1 subscription, it was not working. Have you seen any such behavior on your side? I want to get the improvements in too so want to determine the best path ahead.

To be more specific:

In the functional tests, the subscription tests do not pass(but they can be attributed to the way they are written and need to be updated to be correctly threaded.)

But when I use a sample app where I have 3 subscriptions, and I cancel 1, all 3 seem to get cancelled.

func remove(subscription: MQTTSubscritionWatcher) {
synchronized() {
dictionary.forEach({ (element) in
element.value.allObjects.filter({ $0.getIdentifier() != subscription.getIdentifier() }).forEach({ (watcher) in
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this should be == instead of !=

element.value.allObjects.filter({ $0.getIdentifier() == subscription.getIdentifier() }).forEach({ (watcher) in

Copy link
Contributor

@rohandubal rohandubal left a comment

Choose a reason for hiding this comment

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

I identified a bug which needs to be fixed, it is pretty easy so I might do it if you don't get a chance. Needs additional validation though. I made the above mentioned fix and everything looks good after those changes. I will keep doing some additional validations to make sure there is no breaking behavior.

.travis.yml Outdated
@@ -13,17 +13,17 @@ before_deploy:
- carthage build --no-skip-current
- carthage archive $FRAMEWORK_NAME
script:
- xcodebuild -workspace AWSAppSyncClient.xcworkspace -scheme AWSAppSync build test -destination 'platform=iOS Simulator,name=iPhone 6,OS=latest'
- xcodebuild -workspace AWSAppSyncClient.xcworkspace -scheme AWSAppSync build
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Any reason to remove tests from running in travis to validade PRs?

Copy link
Contributor

Choose a reason for hiding this comment

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

It is definitely a good idea to run the tests on travis. I am working to add some encrypted variables(API URL info, auth information) which would help run the functional tests as well. I will enable along with them 😃

@MarioBajr
Copy link
Contributor Author

Nice catch, will add some tests covering this before submitting the fix.

@rohandubal
Copy link
Contributor

Awesome! I also identified an issue with the existing integration(functional) tests:

https://github.com/awslabs/aws-mobile-appsync-sdk-ios/blob/master/AWSAppSyncTests/AWSAppSyncTests.swift#L231

Here since we are doing let _ = subscribe and not capturing the result, the object is getting de-allocated (rightfully so). The fix in the tests is to hold a strong reference to the returned object. I think we are nearing the merge 😄

- Added tests covering the bug above
- Fixed integration test that were canceling AppSync subscription before fulfilling tests expectations
@rohandubal rohandubal merged commit c69c054 into awslabs:master Sep 11, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants