Some questions: Does a subscription callback count as a request? Does a request that failed e.g. record unique ID conflict or invalidated change token, count as a request? To increase the limit by 10 requests/second, we have to pay $100. Is this a per-day, per-month or per-year charge? Public capacity is scaled by active users. How does CK determine who is an active user? Cheers Glen Low Pixelglow Software try.instaviz.com
To specifically answer your questions:
1. The subscription callback does not count as a request, but any calls you make based on it (such as a sync call to fetch changes in a zone) will count.
2. Yes, failed requests are counted toward the limit.
3. The billing happens on a monthly basis.
4. Any authenticated user who has touched the container within the last 18 months is counted as an active user.
Note that you will never get automatically billed if you have bursty traffic and occassionally hit the ceiling from time to time. Increasing (and paying) for a higher request limit is always opt-in.
Also, for the vast majority of applications the upper free request limit for CloudKit is far above what they will ever need. In the unlikely scenario that your app hits this limit, your requests will get throttled by the server. Make sure your client is always prepare to properly back off and handle throttling responses.
If my app subscribe to a data insert event, for example. Then the app needs to fetch the data, when it gets the subscription data insert callback. However, fetch operation should be counted towards the Cloudkit request limit which is 40 requests/sec, which means if I have more than 40 users. I make run into problems because once a new data is there, all at once all users get subscription notification and try to fetch at the same time?
Did I mis-understand anything? How do I get around?
Does anyone have any answers to joephone's questions regarding notifications?
Won't notifications blow up the system? For example, if you have a thousand users online each with a subscription and then they receive a notification which leads them to make a query/fetch, won't the the majority of the requests fail? Or have I misunderstood something here?
A good concern but not quite as problematic as it seems. First, the user has to tap on the alert to have the app respond. So if your user’s tap response time (take phone out of pocket, look at screen, tap, log in,) is a gaussian at t=6 seconds with a width of 4 seconds the 40 per second limit becomes 320 per alert. Beyond that, the user gets an error message telling them to try in a few seconds. If they do that you can handle 1000 per alert. But then????
This is a real issue. I am trying to work out a solution. Any help would be appreciated.
The problem is...
1) suppose an app has 10,000 users
2) all users subscribe to receive an alert notification when there is a change in a single important record
3) if that record changes only once every month
4) when that record changes many of the 10,000 will open their app at the exact same time after receiving the alert notification, or at most within few seconds of each other
5) If the app then tries to download that changed record the 40/second limit will be hit and it will take over 5 minutes to download the change to the 10,000.
6) This assumes the app does a masterful job of queueing the 10,000 based upon the error CKErrorRequestRateLimited
How do you deal with this issue?
One solution is to include the entire record information in the notification and not query CloudKit after the notification. You could do that using alertLocalizationArgs or desiredKeys. But the value of each key "may be truncated (to 100 characters) when added to the push notification" and desiredKeys is limited to 3 keys. Does anyone know the limit to the number of keys you can have in alertLocalizationArgs and the allowable size of a total notification? Help!
So I used a TSI and was told:
- throttling occurs when the total number of fetches exceeds 40 in a second
- An APN (notification) from a CKQuerySubscription firing can be either 2k or 4k (unclear - they are checking this).
- The notification can contain many alertLocalizationArgs.
- Each alertLocalizationArg can be 100 characters long.
So what I am doing is breaking up my CKRecord (the one I want the app to fetch) into 100 character long strings and placing each string in an alertLocalizationArgs. Then in didReceiveNotificationResponse: I am reconstructing the CKRecord and using that temporarily. I will not do a fetch if the user taps the alert. If the user opens the app normally then I will do a fetch and replace this temporary CKRecord with the real fetched CKRecord. This way a CKQuerySubscription will not result in many simultaneous fetchs exceeding the 40/second limit.