parse-community / parse-server-push-adapter

A push notification adapter for Parse Server
https://parseplatform.org
MIT License
87 stars 99 forks source link

Status 400 and reason BadDeviceToken #87

Open halavins opened 7 years ago

halavins commented 7 years ago

I've updated the parse-server to the latest 2.5.3 version and parse-server-push-adapter v 2.0.0 and now my error logs are full of these messages:

3|parse-wr | node-pre-gyp
3|parse-wr |  
3|parse-wr | ERR!
3|parse-wr |  
3|parse-wr | parse-server-push-adapter APNS
3|parse-wr |  APNS error transmitting to device 28c89bdc6a0e7a6454fb0cc446229a0841eecdea955533d3c549a658bb15fc98 with status 400 and reason BadDeviceToken

There are so many of them that I can't see anything else.

The questions are: 1) How can I ignore these errors in my pm2 config file? 2) Is there a way to remove bad device tokens automatically from Installation Collection?

alexblack commented 6 years ago

I'm pretty sure that a PR could attribute the result (from GCM/APN) back to the installation id, and that seems like the right way to do it.

If that was the case, does that new field resultsByInstallationId look like what we'd want? (The name might be a bit verbose :)

flovilmart commented 6 years ago

So go ahead open he PR. Add the tests, run it in your test environment. Ensure it fits what you need. We’ll discuss after.

alexblack commented 6 years ago

Could we not discuss the requirements up front? If that new field (as I described it) is not what you'd like to see, then best to figure that out now I think.

flovilmart commented 6 years ago

in all those discussions you would have had 10 times the time to implement this and run it, and see if it works for your use case. My gut feeling tells me that it will take you multiple iterations and days running in production to see if this works properly.

alexblack commented 6 years ago

For me, I think it'd make sense for us to have some tentative agreement on what the new field in _PushStatus looks like before getting started.

(Also, we can't get started right away regardless...)

flovilmart commented 6 years ago

We have an agreement that we want to track errors coming back from the push adapter into the _PushStatus object, so a user can at a later time identify which installation has an invalid deviceToken.

I believe this is clear enough as a description, and his gives you the freedom to implement it the way you feel is best. Also if uou’re Not able to start it, either immediately or in a foreseeable future, you don’t really need that feature, nor to discuss it this much is such short amount of time. Again I could be mistaken, but it feels nothing has much moved forward and we’ve both wasted our time on words rather than code, given that what you expect would pretty much take only a few minutes to write and about an hour of adding tests.

alexblack commented 6 years ago

I hear you.

For me, if we had tentative agreement on what the field looked like in _PushStatus that would really help. Without that, I worry that a PR would get rejected or require significant rework if it missed the mark on what this field should look like.

flovilmart commented 6 years ago

And so what if the PR is rejected or require rework? Does it never happen that at code review a better solution arises? Or that when implementing you realize things don’t fit the pre agreed mold? What if the solution is just to write a properly structured log because it works better for you? Wouldn’t it be a waste? Do you believe the time we spend here is not more wasteful than the time it would take to implement, and rework the said PR?

alexblack commented 6 years ago

I thought if we chatted briefly for a few minutes we'd land on what we wanted to see in _PushStatus (even knowing it might change when talk changes to code...) Seemed worth it to me. But I can appreciate if that doesn't seem worth it to you.

flovilmart commented 6 years ago

@halvini please update to the latest version of parse-server that now uses the HTTP/2 interface to APNS. It should yield significantly less logs and open a new issue if it persists.

@alexBlack, I stated my point loud and clear, and you should probably take what I say and work from it. I am not against your proposal, and waiting for an implementation as well as suffisant testing on your side that would ensure we’re not doing all of that for nothing.

alexblack commented 6 years ago

@flovilmart if we had some tentative agreement on what we'd like to see in _PushStatus it would give me the confidence I needed to proceed.

If we can't get agreement there, I'd still hope we can contribute to this great project somehow. Its definitely a huge help for us.

flovilmart commented 6 years ago

Please stop it. What are you expecting? That i’ll Sign off right now on your prospective PR because we agreed on the naming? Ok the name is approved! Now if you want to implement it go ahead!

alexblack commented 6 years ago

What are you expecting?

{
  "resultsByInstallationId": {
    "VvNFL12st4": {
      "succeeded": true,
      "result": {
        "message_id": "0:1526665330066787%b4783826f9fd7ecd"
      }
    },
    "LBsWhDeAMn": {
      "succeeded": false,
      "result": {
        "error": "NotRegistered"
      }
    }
  }
}

I was hoping for some feedback that this looked like what you wanted, or, it didn't.

flovilmart commented 6 years ago

Go ahead with that, and run in on your infra for a week

halavins commented 6 years ago

@flovilmart thanks for the response!

Guys, please don't shoot each other :)

pcg92 commented 6 years ago

same error here backend_1 | node-pre-gyp ERR! parse-server-push-adapter APNS APNS error transmitting to device 7bc3dc72efe2538299e8c775ds58dd0a9a8e8b50794d2 with status 410 and reason Unregistered backend_1 | node-pre-gyp ERR! parse-server-push-adapter APNS APNS error transmitting to device 5b7c2580e1d0bd89d5399338b2c470c0c37c68b3862fc7 with status 400 and reason BadDeviceToken

flovilmart commented 6 years ago

@pcegarra ensure you are using the latest parse server, and the device token is actually valid for your certificate pair.

pcg92 commented 6 years ago

@flovilmart Im sending notifications to all the users but when this error is raided the notification job is stopped. This is actually my code trying to fix this error:

try{
            Parse.Push.send({
                where: installationsQuery, 
                data: {
                    alert: message,
                    badge: 1,
                    sound: 'default'
                }
            },{useMasterKey:true})
            .then(function() {
                    promise.resolve();
            }), function(error) {
                    promise.resolve();
            };
        }
        catch(ex){
            promise.resolve();
        }
        return promise;

Any idea what can I do? I have an android app and two differents ios apps with diferents bundle id example: com.myapp.admin com.myapp.client

so my server config looks like:

ios: [ { passphrase: process.env.PUSH_IOS_PASSPHRASE, pfx: process.env.PUSH_IOS_CERTFILE_DEV, topic: process.env.PUSH_IOS_BUNDLE_ID, production: false }, { passphrase: process.env.PUSH_IOS_PASSPHRASE, pfx: process.env.PUSH_IOS_CERTFILE, topic: process.env.PUSH_IOS_BUNDLE_ID, production: true }, { passphrase: process.env.PUSH_IOS_PASSPHRASE, pfx: process.env.PUSH_IOS_CERTFILE_DEV_2, topic: process.env.PUSH_IOS_BUNDLE_ID_2, production: false }, { passphrase: process.env.PUSH_IOS_PASSPHRASE, pfx: process.env.PUSH_IOS_CERTFILE_2, topic: process.env.PUSH_IOS_BUNDLE_ID_2, production: true },

Could be this the problem?

flovilmart commented 6 years ago

Can you provide the logs when running with VERBOSE=1? Also the state of the associated _PushStatus object for this push?

pcg92 commented 6 years ago

Ok, im going to look with verbose=1, but i dont know how to see the state of the associated _PushStatus object.. Can you explain me it with other words please? thanks!

flovilmart commented 6 years ago

Make a query to the _PushStatus table and get the most recent object. Or with the verbose logs, you should have the objectId associated with it.

pcg92 commented 6 years ago

Parse verbose log:

backend_1 | verbose: _PushStatus a47E2wHCoa: sending push to installations with 1 batches backend_1 | verbose: Sending push to 2 backend_1 | verbose: Sending push to 1 backend_1 | verbose: Sending push to 1 backend_1 | verbose: Sending push to 2 backend_1 | verbose: Sending push to 1 backend_1 | verbose: _PushStatus pdEUFObZ0g: sent push! 0 success, 1 failures backend_1 | verbose: _PushStatus pdEUFObZ0g: needs cleanup devicesToRemove=[APA91bHrIxaqZ2mVv33U89Hsk9mzPQk1d2s_rN2Fw59EhmSU9hAJqgHcw3M2u1MFc3s-IgiYyhmk0Cw-ZWNj6n9g5ljzZGmHrTwBipYLtnNgnRAswc_a7IcC1_7aj0GFRk9cGVod2Sq9] backend_1 | verbose: _PushStatus ztbkBDkM1z: sent push! 0 success, 1 failures backend_1 | verbose: _PushStatus ztbkBDkM1z: needs cleanup devicesToRemove=[dG6GAAOXF_c:APA91bG7vKuW58ni0p3uWnSCEyZn_ZxqRrmG6FSZE3SZrRr9vNnIRwBAff9tZLwvgXbaKwTjoo__qdSdV1xQeajzY3TvVqtsB-NpyV7rhTeccMqAcg8cyw5UJynw_Dw7YqcseBITKGkY] backend_1 | verbose: _PushStatus 44XCEpCDpc: sent push! 1 success, 1 failures backend_1 | verbose: _PushStatus 44XCEpCDpc: needs cleanup devicesToRemove=[cFcF8b-oBEw:APA91bF3aftS13tRQduyF1lUvCr9pcRIV4h1E0J_RrQOKpKOBB9JlxI70MLaH2-EMP0Oh6Oh5iw-swxzF0v80KzfGFH7cUe0X-8wyOaiV1Mrz0sy-izI3HYEQvDRGJ0RNfvdoN6eU1hW] backend_1 | verbose: _PushStatus MHGZ2UPH2F: sent push! 2 success, 0 failures backend_1 | verbose: _PushStatus MHGZ2UPH2F: needs cleanup devicesToRemove=[] backend_1 | verbose: _PushStatus a47E2wHCoa: sent push! 1 success, 0 failures backend_1 | verbose: _PushStatus a47E2wHCoa: needs cleanup devicesToRemove=[] backend_1 | verbose: _PushStatus KKcNQReTQJ: sent push! 1 success, 1 failures backend_1 | verbose: _PushStatus KKcNQReTQJ: needs cleanup devicesToRemove=[finju-C12RI:APA91bGtTbGBXfoDegjganBKoBf_Z8mNo_A-dO18JdCudyQTOKk7qKmtuxpRvbRYG5qa_6cw7IvOGP2AYL1NI6eVvywjDgaUgM9MDsd0wfdxY85zveZ--FkphO1vlcI2xeXg0-J78jTW] backend_1 | node-pre-gyp ERR! parse-server-push-adapter APNS APNS error transmitting to device 7bc3dc72efe2538299e8c7755fdf1a20ca01073eea32b58dd0a9a8e8b50794d2 with status 410 and reason Unregistered backend_1 | verbose: _PushStatus tGmYrDZiaY: sent push! 0 success, 1 failures backend_1 | verbose: _PushStatus tGmYrDZiaY: needs cleanup devicesToRemove=[7bc3dc72efe2538299e8c7755fdf1a20ca01073eea32b58dd0a9a8e8b50794d2] backend_1 | node-pre-gyp ERR! parse-server-push-adapter APNS APNS error transmitting to device dc5dd60549ab890a42f3afb1d47b99d766d2fd8b84ba67152a55b1afcc839b69 with status 410 and reason Unregistered backend_1 | verbose: _PushStatus KiPDDNApW3: sent push! 2 success, 1 failures backend_1 | verbose: _PushStatus KiPDDNApW3: needs cleanup devicesToRemove=[dc5dd60549ab890a42f3afb1d47b99d766d2fd8b84ba67152a55b1afcc839b69]

Query id for KiPDDNApW3 { "results": [ { "objectId": "KiPDDNApW3", "pushTime": "2018-05-26T12:23:40.842Z", "query": "{\"restaurant\":{\"__type\":\"Pointer\",\"className\":\"Restaurant\",\"objectId\":\"6FgXTZOtI0\"}}", "payload": "{\"alert\":\"¿Que hay de comer en \\\"Tayo’s\\\"?\",\"badge\":1,\"sound\":\"default\"}", "source": "rest", "status": "succeeded", "numSent": 2, "pushHash": "ed5d0f1208f198fc8d337b2105a53b28", "createdAt": "2018-05-26T12:23:40.842Z", "updatedAt": "2018-05-26T12:23:43.183Z", "numFailed": 1, "sentPerType": { "ios": 2 }, "failedPerType": { "ios": 1 }, "ACL": {} } ] }

flovilmart commented 6 years ago

From what I can see, everything is fine for that push. In your logs we see at least 3 different pushs intertwined, but, the one with the push status look good, as the expected number of pushs is 3 and the total send / failed is 3 as well

mtrezza commented 6 years ago

@flovilmart I've tested PARSE_SERVER_CLEANUP_INVALID_INSTALLATIONS with development certificates in APNS sandbox and it worked just fine.

It always takes me about 5 remote push notifications within 5 minutes until APNS reports a failed push and the bad device token gets removed. It worked several times, the good device tokens untouched, the bad ones removed.

Parse server push configuration:

push: {
        ios: [
            {
                pfx: 'apns_dev.p12',
                topic: 'com.myDomain.myApp',
                production: false
            }
        ]
    },

Tested with: parse-server v2.7.4 and v2.8.1

@halvini's case sounds like some kind of mix-up of production and development APNS certificates / device tokens. Note that my parse server configs only includes one APNS certificate per server.

Looking at the code I suspect the following cause:

Each push certificate creates a provider. The list of providers is sorted by production certificates before development certificates. When sending a push notification, the production provider is tried first, if it fails the development provider is used. Now if a push using an APNS production device token that is sent through the production provider fails for any reason, the push is sent through the development provider, which will identify it as a bad device token. This leads to the removal of the token in parse server because it has been sent to the wrong environment. So in @halvini's case the APNS production server could simply have been unreachable for a brief moment, 3 days after activating the clean-up flag, causing the removal of the good device tokens.

If that is the cause of the problem, a solution could be to add a production: Bool field to the Installation document to flag the device token as either production or development. The push sending logic then has to be changed to send production tokens only to production providers and development tokens only to development providers.

Another solution would be to simply remove the possibility of adding development certificates to parse server in a production environment, i.e. remove the production key from the parse push configuration. A development / testing environment should be sandboxed from any production environment anyway. This would be my preferred solution.

mtrezza commented 6 years ago

@flovilmart, this issue is closed, but can you confirm or dismiss my analysis above?

flovilmart commented 6 years ago

Yeah it’s possible that the errors reported when using multiple certificates in production may be problematic. I’ll reopen while we find a proper workaround

allanberrocal commented 5 years ago

Hi, I'm having the issue when sending push notification to iOS. Error

node-pre-gyp ERR! parse-server-push-adapter APNS APNS error transmitting to device ...f6r4... with status 400 and reason BadDeviceToken

We have the latest version of parse. One production certificate, no dev. Push notifications worked well for iOS devices for a day, but not afterwards. Not even new installations of iOS are not receiving the notifications.

We were using the token-based authentication (w/ .p8 file) when Push stopped working. Them moved to signing certificate (w/ .p12 file), but with no better luck. Anyone is having or has had this issue? Ideas?

Thank you

davimacedo commented 5 years ago

Can you please open a new issue and fill out the template?