This is indeed caused by unrealistic heartbeat intervals in Google Cloud Messaging.
This is possibly the most frustrating bug in GCM. GCM works by maintaining an idle socket connection from an Android device to Google’s servers. This is great because it barely consumes battery power (contrary to polling), and it allows the device to be woken up instantly when a message arrives. To make sure that the connection remains active, Android will send a heartbeat every 28 minutes on mobile connection and every 15 minutes on WiFi. If the heartbeat failed, the connection has been terminated, and GCM will re-establish it and attempt to retrieve any pending push notifications. The higher the heartbeat interval, the less battery consumed and the less times the device has to be woken up from sleep.
However, this comes at a great price: the longer the heartbeat interval, the longer it takes to identify a broken socket connection. Google has not tested these intervals in real-life situations thoroughly enough before deploying GCM. The problem with these intervals is caused by network routers and mobile carriers, who disconnect idle socket connections after a few minutes of inactivity. Usually, this is more common with cheap home routers, whose manufacturers decided on a maximum lifespan of an idle socket connection, and terminate it to save resources. These routers can only handle a finite number of concurrent connections, and so this measure is taken to prevent overload. This results in terminated GCM sockets, and when the time comes to deliver a GCM message, it does not reach the device. The device will only realize that the connection has been broken when it’s time to send a heartbeat, 0 – 28 minutes later, rendering the push notification useless in some situations (when the message is time-critical, for example). In my experience, most cheap routers terminate idle connections after about 5 – 10 minutes of inactivity.
I wrote an entire post about this and other GCM issues:
http://eladnava.com/google-cloud-messaging-extremely-unreliable/
An Alternative to Google Cloud Messaging
Pushy (https://pushy.me/) is a standalone push notification gateway, completely independent of GCM. It maintains its own background socket connection, just like GCM, to receive push notifications. The underlying protocol is MQTT, an extremely light-weight pub/sub protocol, utilizing very little network bandwidth and battery.
A huge advantage of Pushy is that the code for sending a push notification (from the server), and registering the device for push notifications, is actually interchangeable between GCM and Pushy. This makes it super easy to switch to Pushy after implementing GCM and having to ditch it for its instability.
(Full disclosure: I founded Pushy for my own projects and realized many apps would benefit from such a service)