kriskowal / q

A promise library for JavaScript
MIT License
14.93k stars 1.2k forks source link

TypeError: Q.nextTick.runAfter is not a function #764

Open nandreev211 opened 8 years ago

nandreev211 commented 8 years ago
var answer = q.defer();
var replyQueue;
function MaybeAnswer(msg) {
       answer.reject(new Error(msg.content.toString()));
 }

return ch.assertQueue(toQueue, queueOptions || this.queueOptions)
                            .then(function () {
                                return ch.assertQueue('', this.replyQueueOptions);
                            }.bind(this))
                            .then(function assertQueueSuccess(qok) {
                                replyQueue = qok.queue;
                                return ch.consume(replyQueue, MaybeAnswer.bind(this), {noAck: true});
                            }.bind(this))
                            .then(function consumeSuccess() {
                                ch.sendToQueue(toQueue || this.queue, new Buffer(msg), props);
                                return answer.promise;
                            }.bind(this))
                            .catch(function (error) {
                                // Return Error to the outer .catch()
                                this.logger.error(error);
                                return q.reject(error);
                            }.bind(this))
                            .finally(function () {
                                if (this.standalone) {
                                    conn.close();
                                }
                                else {
                                    ch.close();
                                }
                            }.bind(this));

While running above code I'm getting an error

TypeError: Q.nextTick.runAfter is not a function

stack trace: at trackRejection (/Volumes/DATA/projects/cirrent/api-dev/node_modules/q/q.js:1059:20) at reject (/Volumes/DATA/projects/cirrent/api-dev/node_modules/q/q.js:1133:5) at deferred.reject (/Volumes/DATA/projects/cirrent/api-dev/node_modules/q/q.js:634:16) at Object.MaybeAnswer (/Volumes/DATA/projects/cirrent/api-dev/node_modules/API-Common/helpers/rpc.js:98:44) at Channel.BaseChannel.dispatchMessage (/Volumes/DATA/projects/cirrent/api-dev/node_modules/amqplib/lib/channel.js:466:12) at Channel.BaseChannel.handleDelivery (/Volumes/DATA/projects/cirrent/api-dev/node_modules/amqplib/lib/channel.js:475:15) at emitOne (events.js:77:13) at Channel.emit (events.js:169:7) at /Volumes/DATA/projects/cirrent/api-dev/node_modules/amqplib/lib/channel.js:263:10 at Channel.content as handleMessage

I really couldn't find out what's gone wrong with my code. I'd appreciate if anyone can help with this.

DeusExLibris commented 8 years ago

I just started seeing this issue as well in a section of code that has not been touched in months. It doesn't happen in my development environment - only in my staging environment. It doesn't look like any of my module dependencies have changed either. If I find a solution I will post back here.

kriskowal commented 8 years ago

Might be useful to share versions of Node.js and perhaps any modules that might be monkey-patching nextTick. Maybe do a search for occurrences of runAfter. There are no direct references to nextTick.runAfter in Q.

DeusExLibris commented 8 years ago

Here is the relevant part of my package.json: "dependencies": { "apn": "^1.7.5", "binaryjs": "^0.2.1", "body-parser": "^1.14.0", "bufferutil": "^1.2.1", "compression": "^1.6.0", "connect-mongodb-session": "^1.0.6", "cookie-parser": "^1.4.0", "ejs": "^2.3.4", "express": "^4.13.3", "express-session": "^1.12.1", "express-stormpath": "^2.1.0", "express-ws": "^0.2.6", "fluent-ffmpeg": "^2.0.1", "moment": "^2.10.6", "moment-timezone": "^0.5.0", "mongodb": "^2.0.47", "mongoose": "^4.2.4", "multer": "^1.1.0", "newrelic": "^1.23.0", "numeral": "^1.5.3", "q": "^1.4.1", "sharp": "^0.11.4", "stormpath": "^0.13.4", "twitter": "^1.2.5", "winston": "^2.1.0", "winston-mongodb": "~1.2.0", "xml2js": "^0.4.15" }, "engines": { "node": "^5.0.0", "npm": "^3.3.10" }

DeusExLibris commented 8 years ago

Interestingly, I only have this problem on a single (virtual) machine. Even when I deploy the same setup to a different server (i.e, my qa server), it works fine.

Also, not sure what you mean when you say "There are no direct references to nextTick.runAfter in Q." It is defined in q.js line 240, making it all the stranger that it doesn't find it.

DeusExLibris commented 8 years ago

BTW, thanks for such a quick response.

DeusExLibris commented 8 years ago

I have fixed my issue. In copying and pasting my package.json, I realized there were a couple of modules that I wasn't using any longer and removed them (grunt-git, grunt-spritesmith, throttle and signal-master). I also removed a "require" reference to one of the modules which was never being called (throttle). When I redeployed to the server that was reporting this error, the problem went away.

Not sure if this helps @nikolay211 or not, but I thought I would at least report how I resolved it.

Thanks again for the response.

kriskowal commented 8 years ago

Pardon, I was on the wrong branch. Q does in fact have a nextTick.runAfter now.

mdressman commented 8 years ago

We've just been bitten by this issue as well, after an upgrade to node v4 and latest versions of React, etc. We've not yet found a solution.

kriskowal commented 8 years ago

Would anyone be able to Q.nextTick.toString() and manually verify that nextTick.runAfter is missing? Sounds like something is monkey-patching Q.

mdressman commented 8 years ago

looks like it was the node-newrelic module. they just released a fix today. https://github.com/newrelic/node-newrelic/commit/8042f18e65cdbfa9c1acf13e39f28483741a3944

kriskowal commented 8 years ago

Thanks @mdressman. Let’s keep this issue open to track how Q can be more resilient against this kind of monkey-patching. nextTick should close over its runAfter dependency instead of exposing it as public API.

benjamingr commented 8 years ago

The rationale was to let people change the scheduler kind of like bluebird's setScheduler. I don't think we should explicitly hide it.

kriskowal commented 8 years ago

Perhaps we can move it to a top level hook. On Tue, Feb 23, 2016 at 12:56 AM Benjamin Gruenbaum < notifications@github.com> wrote:

The rationale was to let people change the scheduler kind of like bluebird's setScheduler. I don't think we should explicitly hide it.

— Reply to this email directly or view it on GitHub https://github.com/kriskowal/q/issues/764#issuecomment-187606563.

zamb3zi commented 8 years ago

Any news on this? I would also like to change the scheduler for use with Angular where I would require all handlers to execute within the digest cycle. This is done in angular-bluebird-promises using bluebird's setScheduler as follows.

  ...
  .run(function($rootScope, Bluebird) {
    Bluebird.setScheduler((cb) => $rootScope.$evalAsync(cb));
  });

Thanks.

benjamingr commented 8 years ago

As the person who suggested the scheduler APi for bluebird I'll gladly implement an API for Q for the same thing if Kris asks.

zamb3zi commented 8 years ago

In the meantime, the following appears to work for Angular:

// monkey-patch Q so that it schedules tasks during the digest cycle.
const angularNextTick = task => () => $rootScope.$evalAsync(task);
const {nextTick} = Q;
Q.nextTick = task => nextTick(angularNextTick(task));
const {runAfter} = nextTick;
Q.nextTick.runAfter = task => runAfter(angularNextTick(task));

And here is a simple test to confirm that it's always $digest phase:

setInterval(() => {
    Q.delay(10).then(() => console.log('$$phase =', $rootScope.$$phase));
}, 100);
landonpoch commented 7 years ago

@zamb3zi , Attempting your workaround, runAfter comes back as undefined when destructuring nextTick after reassignment. I'm using q@1.4.1.