Meteor-Community-Packages / meteor-collection-hooks

Meteor Collection Hooks
https://atmospherejs.com/matb33/collection-hooks
MIT License
657 stars 92 forks source link

Question: disabling and re-enabling #47

Closed cramhead closed 10 years ago

cramhead commented 10 years ago

Is there a good approach for disabling a collection hook after it has been set. I've tried setting the listeners to null or an empty function, e.g. Collectibles.after.insert(function(){}); and Collectibles.after.insert(null); as well as Collectibles.after.insert = null; but the handlers I had previously set still get called or when I attempt re-enable listeners TypeError: Property 'insert' of object #<Object> is not a function.

Thanks

mizzao commented 10 years ago

I don't know if the answer to your question specifically is yes, but there are two workarounds:

matb33 commented 10 years ago

When you register a hook, it returns an object with .remove and .replace. In your case you're looking for .remove

cramhead commented 10 years ago

Oh, that's awesome. Basically a handle that I can hold onto and remove handler later. I expect that will be much easier then adjusting all the collection call. Thanks so much to both of you.

cramhead commented 10 years ago

So I think I may have stumbled across a more significant problem, assume that my code below is doing what is expected. I'm assuming that I simply call the remove method on the object returned add hood methods. Below, when adding a handlers I add push the returned object into an array when a call to initCollectionHooks is called and when disableCollectionHooks is called objects are popped from the array and their remove method is called, with no arguments.

var hookHandles = [];

var initCollectionHooks = function() {
  console.log('enable');
  //once the seed process is complete or no seeding takes place add the listener
  hookHandles.push(
    Collectibles.after.insert(function(userId, doc) {
      // get the imageIds and set them as being linked
      App.emitter.emit('collectible.added', userId, doc);
    })
  );

  hookHandles.push(
    Collectibles.after.update(function(userId, doc, fieldNames, modifier, options) {
      if (fieldNames.indexOf("favs") > -1) {
        if (modifier.$push) {
          collectibleFaved(userId, doc);
        }
        // no notification on $pop
      }
    })
  );
};

var disableCollectionHooks = function() {
  console.log('disable');
  for (var i = hookHandles.length - 1; i >= 0; i--) {
    console.log('removing collectible hooks');
    var hookHandle = hookHandles.pop();
    hookHandle.remove();
  };
};

// start with hooks enabled
initCollectionHooks();

// listen for seed events and turn off/on collection hooks
App.emitter.on('seeding.started', disableCollectionHooks);
App.emitter.on('seeding.completed', initCollectionHooks);

My issue seems to be an interaction between collectionFS and collection-hooks, when I attempt insert seed images. I've tried disabling the hooks and never adding them, but I still get the error below. CollectionFS fails, but when we look further down there is a CollectionHooks.defineAdvice.arg entry in the stack. Any thoughts?

I20140625-14:25:17.948(-7)?     at Request.pipe (/Users/cram/.meteorite/packages/data-man/CollectionFS/Meteor-data-man/c42e97728b38c29522d59db58d290e928df831ba/.build/npm/node_modules/request/request.js:1299:13)
I20140625-14:25:17.948(-7)?     at beginStorage (packages/cfs-collection/api.common.js:32)
I20140625-14:25:17.948(-7)?     at packages/cfs-collection/api.common.js:61
I20140625-14:25:17.948(-7)?     at _.each.Meteor.Collection.(anonymous function).wrappedCallback (packages/mongo-livedata/collection.js:431)
I20140625-14:25:17.949(-7)?     at CollectionHooks.defineAdvice.args.(anonymous function) (packages/collection-hooks/insert.js:35)
I20140625-14:25:17.949(-7)?     at Meteor.bindEnvironment.runWithEnvironment (packages/meteor/dynamics_nodejs.js:108)
I20140625-14:25:17.949(-7)?     at Meteor.bindEnvironment (packages/meteor/dynamics_nodejs.js:121)
I20140625-14:25:17.950(-7)?     at writeCallback (packages/mongo-livedata/mongo_driver.js:293)
I20140625-14:25:17.950(-7)?     at Meteor.bindEnvironment.runWithEnvironment (packages/meteor/dynamics_nodejs.js:108)
mizzao commented 10 years ago

I believe the CollectionHooks.defineAdvice.args always runs if collection-hooks are added, even if there are no hooks configured on the collection. Otherwise it wouldn't be able to intercept them. Why don't you look into the specific message Error: You cannot pipe after data has been emitted from the response.? That seems to be what's causing this.

cramhead commented 10 years ago

That what I'm in process of doing. It's pretty complicated code with all the futures calls and bindEnvironment. I figure I should try disabling collection-hooks to remove it form being a potential problem first.

matb33 commented 10 years ago

Any luck @cramhead?

matb33 commented 10 years ago

For your specific use-case, could you wrap all of your hooks in a function that checks a variable (probably using Meteor.EnvironmentVariable) so as to decide whether or not to run the hooks?

The idea would be that when you set this flag to false, the function wrapping your hooks would simply short-circuit and not execute the hook. If the flag is true, calls the hook as per normal.

mizzao commented 10 years ago

@cramhead: See https://github.com/mizzao/meteor-partitioner/blob/master/grouping.coffee#L140 for an example of how to implement @matb33's suggestion.

cramhead commented 10 years ago

Hi guys, Thanks so much for your help. Sorry I forgot to close the issue.

I've a sample of the approach up in a gist at https://gist.github.com/cramhead/dc431ab0417fce7aa965. The code basically listens for events emitted when seeding data and when seeding is complete. The event handlers look in a list of collection-hook handlers to determine what functions need to be removed and removes them.

I do think the issue rests in collectionFS. I'll be pursuing the collectionFS issue when I can find a small block of time.