I have seen many tutorials and opinions on that - I have developed a simple script that will send batches of notifications to Apple servers, and I crontask it every 5 seconds. (it's php so far, should be improved soon).
This way, the code is simple, and if 1 batch is larger, it will not delay the next batch. It also allows to run on multiple servers to dispatch faster and solves any concurrency issues
However, I am not clear about Apple tolerance to the fact that I open/close a socket with them every 5 seconds... In sandbox mode, it works perfectly.
Thanks for the advice
How about this approach:
- batch all in some data-structure (I don't know about PHP, but in Objective-C this would be a NSArray containing instances of some custom NotificationClass or NSDictionaries).
- if you have either A) batched up more then X notifications you send them through, or B) waited a certain time (e.g. 5 seconds).
Depending on what you use the push notifications for you can adjust these variables. A chat app for example want them to be sent immediately, while some daily messaging app would probably be OK with sending them all at once each hour or so.
Also, Apple's words on opening connections:
You may establish multiple connections to the same gateway or to
multiple gateway instances. If you need to send a large number of push
notifications, spread them out over connections to several different
gateways. This improves performance compared to using a single
connection: it lets you send the push notifications faster, and it
lets APNs deliver them faster.
Keep your connections with APNs open across multiple notifications;
don’t repeatedly open and close connections. APNs treats rapid
connection and disconnection as a denial-of-service attack. You should
leave a connection open unless you know it will be idle for an
extended period of time—for example, if you only send notifications to
your users once a day it is ok to use a new connection each day.
See here for official docs (Best practies for Managing Connections).
The idea is that you simply leave the connection open between the batches.
In fact, Apple recommends you create multiple connections, so you can divide the 1000 over maybe five or ten or so connections. You could have some connection manager in your code that controls the lifetime of the connections: if no messages have been send trough for x amount of time, shut it down. If some piece of client-code requests a connection, this manager either creates a new one, or returns one that is not currently being used to send data through. The client of this manager should be prepared to not receive a connection, and the connection manager should in turn notify clients about the availability of connections.
Lots of possibilities in terms of architecture, but the main point it is better to leave a connection open and idle for some time, then to open and close them many times.
Related
I'm working on a feature on iOS for which we want to query a Firebase realtime database, which only updates about once a week. I saw there is a limit of 200k simultaneous connections (for the Blaze plan). My question is: what counts as an active connection?
For example, if we create an observation using the .observe() method, does that mean 1 connection as long as we are observing?
And what about a 'one shot' fetch, using .getData(). Does this close the connection after completion?
We're not actually interested in keeping an observation alive for a long time, as data only changes about once a week.
From the frequently asked questions:
A simultaneous connection is equivalent to one mobile device, browser tab, or server app connected to the database. Firebase imposes hard limits on the number of simultaneous connections to your app's database. These limits are in place to protect both Firebase and our users from abuse.
The SDK connects to the server the first time that you try to access data from (or write data to) the database. The connection stays open for as long as the client has an active listener (so observe in your case) or until about 5 minutes after the last read or write operation.
You can also explicitly control the connection by calling goOffline and goOnline in your code.
Take an iOS app like Instagram. Instagram is fundementally a real-time application that updates its UI whenever a user interacts with you. For example, if someone likes your post and you are using the app, the UI is updated to trigger dopamine release and inform you that something has hapened to one of your posts. Similarly, when someone sends you a direct message on instagram, while using the app, you see the message spring down from the top, all in real-time.
In terms of implementing such real time features it is obvious that a naive HTTPS polling approach is far too inefficient. Thus this leaves two strategies:
1.) APNS Push Notifications:
When a user likes a post, sends a direct message, comments (etc.), send an HTTP POST to a backend server that will then update the database and send a silent Apple push-notification to the device of the recipient. The recipient, which is using the app, will receive the pushed payload and will send an HTTP GET to the backend server to fetch the needed data (ie. the contents of the direct message sent). The UI is updated in quasi "real-time".
2.) Websockets:
Whenever any user opens the iOS app, connect the user to the server via a websocket. This means, that all users currently using the app are connected to the server via their own websocket. When a user likes a post, sends a direct message, comments (etc.), the app sends a message to the server through the socket indicating the action. The server, before updating the database, finds the socket associated with the recipient and forwards the message through the socket to the recipient. Upon reception of the message, the UI is updated in real-time
Which of these approaches is scalable and better suited for a production environment?
TL;DR You'll love websockets + Combine framework, event driven to update your UI smoothly. APNS can be somewhat unreliable in terms of deliverability and resource/database costs, and to me is more of an information center.
Reasons to like websockets:
Decreases DB costs (e.g. finding device to send to)
You know when the user is not using the app, decreasing outbound data costs
Latency and faster practically speaking (more in depth in the websocket paragraph)
To answer the question: websockets are scalable based on your user count obviously. APNS is not server side testable in the CI, not cross platform, and not exactly feasible in terms of resource consumption.
I have a bias with websockets. But to present why I like it more, think about the efficiency given by your Instagram example.
To me, websockets == Event Driven, APNS is a simple information center.
APNS:
You sign up with APNS and you save the device in your backend. Great, every time an action is performed, like someone liking your post, query your backend, find the device that is linked to the OP, then send it outbound (which costs money if you think cloud computing costs). And you have to do that every single time someone likes your post (obviously you can aggregate, but why bother when you have websockets?). So database costs is one thing to think about. Additionally, a user could be muting their notifications. I don't have Instagram, but something efficiency wise they could have done (if not by sockets) is updating their UI based on incoming notifications for likes/hearts rather than a websocket connection. That's slow in terms of latency, costly, and unreliable if marked as spam. However, APNS has the benefit of not needing authorization unlike websockets, but...
Websockets:
When we approach websockets, you only authorize once (at least for mobile applications). You're removing outbound data costs (in terms of $$ and latency) by removing stuff like headers. You want to send small chunks of data, and sockets are just sending text/binary (I like to create commands out of them using JSON. A notable example is GitHub). When your user is done with the app, you close the connection and you don't need to send anymore data via APNS. Your server itself can be communicating with a single websocket via something like Redis PubSub in order to update your UI when someone uses a POST request to heart a post without needing to send some push notification. That's a win for the liker (who doesn't need to wait for that push notification to be sent) or the other way if you offload it to a background task (the OP doesn't need to wait). Websockets == Event Driven:
Small data chunks that are constantly delivered (as in a lot) is much better than having APNS in which it can be slow to actually deliver, especially if you're flooding Apple/your user with notifications, marking you as spam. Although, disclaimer, that's just my personal belief and speculation depending on your use case.
You're removing those unnecessary database costs.
A downside would be keeping the connection alive.
Personally, I've used websockets with the combine framework recently for a chat application, but it can be used in so many different circumstances. Updating a Facebook feed/comment section, live notifications via the websocket instead of APNS, even posting content.
APNS is not guaranteed to be delivered, especially if you have a lot of notifications - I don't remember where I read that, but after some threshold per min it'll stop working. Also, you'll have to send them to all your users, not just online ones. It's possible to send silent notifications, but it's still not optimal.
That's why websocket is a preferred way. Also you can use something like https://github.com/centrifugal/centrifugo, which is a helper for your server, that'll hold all the connections, and is very stable.
It is not one out of two, even the web-socket isn't failsafe, but all of above should be considered for an effective communication, when the app is in foreground use a web-socket to listen for any updates from the server, expect a confirmation from client when something is delivered by socket, if the web-socket connection is not active or the there is no confirmation response deliver the update through APNS/FCM, as APNS/FCM it is not guaranteed to deliver, deliver the updates when next Socket connection is successful.
If I want to make sure that a device receives a message, over the network, for an app used by sellers in a shop for example.
I heard push notifications are not 100% reliable, sometimes some of the notifications don't arrive, or not on time.
The app could be in a shop, where the staff communicate with one another, and there could be 10 devices connected. (ipad, iphones)
edit 1: I heard about sockets, is it the right direction to go?
EDIT 2:
I am not sure why a socket should be used, rather than a webserver for example, I found these 2 sentences (source raywenderlich) :
You can send connected clients data whenever you want, rather than requiring the clients to poll.
You can write socket servers without a dependency of a web server, and can write in the language of your choice : don't understand what the "dependency" is?
Does it also mean :
Sockets let 2 (or more) specific devices to connect one another in a private connection, compared to webservers where everybody could connect if there is no login/password?
EDIT 3 : Maybe a bluetooth solution with MultiPeerConnectivity would be better...
Sockets, and push notifications in general, are only as reliable as the network the user is connected to. If your looking to circumvent network reliability where a 100% success rate is guaranteed, in a Shop environment where users are in close proximity, you can look into GKSession as part of the GameKit.framework
Or you could look into Bonjour or client/service discovery protocols that makes the process of "knowing" peers in a network
I see you tagged Parse.com, again, the reliability of Push Notifications is highly dependent on the reachability, however, most issues that arise with Parse is dev-end related, not product related.
EDIT I forgot to mention MultiPeerConnectivity
If you use TCP sockets, you are guaranteed the message will be delivered, and very quickly too.
However, the application would have to be open (and most likely in the foreground) to receive the messages. You can always have the server wait till the client connects to send the message.
I would suggest using a combination of both TCP sockets and push notifications (for when the app is closed).
I understand the basic concept of having a provider talk to Apple's Push Notification Server which then pushes the notification to the phone. Usually, the provider is an app server running on some machine somewhere completely separate from the app.
However, we don't currently have a separate server, and don't yet need one as everything is currently handled in-app. So, is there any way we can use the app itself as the provider to send a notification to Apple's server and thus to another phone?
Basic concept: we have a game and when a user completes 70% of the level, we'd like to notify his competitors that he's close to finishing the game (or that he has finished at 100%).
If it's possible, are there any security concerns with this approach?
P.S. The app already knows who the competitors are because it displays them in a UITableView.
Technically it's possible. If you include the push certificate with your app, and you have a way to send the device token of each device to all other devices that may need to push to that device, you can push a notification directly from one device to another.
However, in practice, that would require opening and closing many connections to the APNS servers frequently (you'll need a connection for each device, and every time a device loses network connection - which may happen often - you'll have to re-open that connection), which will probably cause Apple to block your app from connecting to their APNS server (since they would interpret it a DDoS attack).
Therefore you should use a server.
For future visitors to this question: we wound up ditching Amazon SNS since we spent nearly 8 hours and couldn't get it working the way we wanted. Instead, we setup Parse Push in rough 15 minutes with exactly what we wanted to do, so I would definitely recommend giving it a look.
I am quite new into programming and I cant find efficient solution for my problem. Could someone point me in the right direction please?
I have an app which is heavily relying on server data. Data on server is unique for each user and may change every minute as well as only every few hours. Currently I am updating local data when app becomes active but I also need a way of notifying app to trigger updates when app stays in active state and data has changed on server. I thought about few solutions:
1) NSTimer set to one minute and triggering url request to check if there is new data on server. Server after comparing lastModified value would return new data if available.
I don't really like that solution as I don't want to overload my server with number of requests, especially that data in the database may change only every few hours or even longer.
2) APNS - sending notifications from server every time data will change and than update local data with server database when notification received.
It seems like a good solution but only if it would be possible to restrict remote notifications to be received when app is in active state. As far I know it is not possible and as I mentioned before data may change even every minute so I don't want to spam users with number of notifications when app is not running.
3) TCP Sockets using NSStream/CFStream?
This is something I never did before, so I am not even sure if I am going in the right direction researching about this one.
This is a hard topic in general, but more technologies are coming out to help with it. Couple thoughts on each of your solutions:
The NSTimer solution is effectively polling, which is the worst option I feel. You'd be hitting your server pretty hard for each user.
This would be a better solution. APNS now supports silent notifications, so you can send push notifications to a user without worrying about notifying them. You can send a silent notification by including the content-available key in the payload and not including the alert key. More info here: http://hayageek.com/ios-silent-push-notifications/. It is rate limited, though. You may go minutes to hours without getting a delivery, so if that's important you'd be best to go to option 3.
This is your best solution. It would require a persistent connection with your server. AFNetworking 2.0 supports this kind of connection based on Rocket. Here's Rocket's documentation: http://rocket.github.io. Take a look at server-sent events.
Hope that helps!