wechaty / wechaty-puppet-padplus

DEPRECATED: One puppet based on iPad protocal for Wechaty
https://wechaty.js.org/docs/puppet-services/
315 stars 65 forks source link

Sometimes promise is not resolved despite message having been sent and no errors or anything are thrown i.e. resulting in the whole rotinue just getting stuck there (Probably because the GRPC server is encountering a high volume of traffic) #272

Open archywillhe opened 4 years ago

archywillhe commented 4 years ago

Is your feature request related to a problem? Please describe.

Realted to https://github.com/wechaty/wechaty-puppet-padplus/issues/267

But this is the case where no errors are thrown and the whole thing just got stuck there.

A clear and concise description of what the problem:

Sometimes the promise is not resolved despite message having been sent by the bot and no errors or anything are thrown i.e. resulting in the whole rotinue just getting stuck there.

e.g.

Screenshot 2020-07-05 at 12 35 46 PM Screenshot 2020-07-05 at 12 29 46 PM

where "getting article.." is never logged and the whole routine just got stuck. Look like it's cuz the GRPC server is busy (though the message manages to reach the server & been sent by the bot)

Describe the solution you'd like

Maybe a time-out on the client-side? And throw a descriptive error?

Would be nice to have some kind of fall-back mechanism

Describe alternatives you've considered

(Right now I will implement an ad hoc fall-back mechanism in my backend. If more people think this should be a built-in feature maybe I will fork and integrate it into the lib (after code is refacotred) and will do a PR)

archywillhe commented 4 years ago

okay so this is where i got stuck

3:37:58 VERB Message say(分析文章中哦~)
13:37:58 SILL PuppetPadplus messageSendText(wxid_w2rilkb6i30t32, 分析文章中哦~)
13:37:58 VERB Puppet selfId()
13:37:58 SILL PadplusManager selfId : wxid_fg82oeyn3p3y22, receiver : wxid_w2rilkb6i30t32, text : 分析文章中哦~, type : 1
13:37:58 VERB PadplusMessage sendMessage()
13:37:58 SILL RequestClient request()
13:37:58 SILL DedupeApi dedupe() no need to dedupe api SEND_MESSAGE.
13:37:58 SILL GRPC_GATEWAY GRPC Request ApiType: SEND_MESSAGE

sometimes it stuck here forever without throwing a timeout error,

sometimes it threw the same timeout error as I had described in #267:

12:11:05 ERR GRPC_GATEWAY ApiType: GET_CONTACT_SELF_INFO request timeout, traceId: 37a509db-4ebb-424b-9527-fdf3b5a260fa
(node:5887) UnhandledPromiseRejectionWarning: Error: can not get callback result of GET_CONTACT_SELF_INFO
    at PadplusContact.<anonymous> (/Users/arch/archy-the-anki-bot/node_modules/wechaty-puppet-padplus/src/padplus-manager/api-request/contact.ts:293:13)
    at Generator.next (<anonymous>)
    at fulfilled (/Users/arch/archy-the-anki-bot/node_modules/wechaty-puppet-padplus/dist/src/padplus-manager/api-request/contact.js:5:58)
(node:5887) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 2)
(node:5887) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

So there are two werid things here.

  1. the timeout error doesn't always get thrown.

  2. And when it gets thrown, the werid thing is that I'm not able to catch the timeout error with try...catch on await msg.say.

Screenshot 2020-07-05 at 12 29 46 PM

How should this error be catched in my back-end?

Hmm so i took a look into the code and saw that this error is created in line 294 of contact.ts

throw new Error(`can not get callback result of GET_CONTACT_SELF_INFO`)

and the error message is logged by line 269 of grpc-gateway.ts

  log.error(PRE, `ApiType: ${ApiTypeDic[apiType]} request timeout, traceId: ${traceId}`)

So maybe we need to have a catch for line 555 in padplus-manager.ts


                return this.contactSelfInfo()
                  .then(async contactSelfInfo => {
                    if (contactSelfInfo) {
                      const contactSelfPayload = convertFromGrpcContactSelf(contactSelfInfo)
                      if (!this.cacheManager) {
                        throw new Error(`no cache manager`)
                      }
                      return this.cacheManager.setContact(contactSelfPayload.userName, contactSelfPayload)
                    } else {
                      throw new Error(`can not get contact self info.`)
                    }
                  })

so the error get propagated to the promise in the back-end?

Or what should be done?

archywillhe commented 4 years ago

Have anyone had any luck catching and handling this timeout error in the backend instead of running into UnhandledPromiseRejectionWarning: Unhandled promise rejection?