[SOLVED] What could prevent change observer?

I currently ran into the issue where my updates are not reflected by the publication anymore. The Chrome devTools extension shows that the subscription is ready, the documents are added and that the update Method has been successful. The mongo shell also shows the updated document.

However there is no change DDP message after the update and when I reproduce this behavior using a minimal app it actually works. So I am really out of my options here what could prevent this change observer here?

I have also subscriptions to external Meteor apps via DDP connection and they face the same issue.
Anyone has an idea how to get to that level? Where do I need to check for the update changes actually dispatching the change callback? I know this is some observer but can I access it and debug it?

Edit: even after reloading the app several times the update is not reflected but magically after a certain amount of time it is. This is totally unusual as I have never seen such behavior before.

Are you doing anything “funky”? I’ve seen this before when dealing with manual publications, specifically with overlapping subscriptions, where the _id of the returned document remains the same, and two different subscriptions are temporarily requesting the same document, but the data is different. The “issue” in this case is in the merge box (really the issue is in the code that deals with this). I mention it because the issue goes away when the “first” subscription ends. Which might explain the “amount of time”

I’d suggest cloning the ddp-server package and putting some console logs in the added/changes functions of the session and view objects.

1 Like

Are you doing anything “funky”?

Actually I did :laughing:

After wasting hours of git diffs between commits and submodule commits I finally found the issue. I am extending EJSON to support RegExp natively, which itself works when testing as package with unit tests but I haven’t thought that integrating it actually may have such consequences…

It acutally fails when using the native RegExp class:

import { EJSON } from 'meteor/ejson'

function getOptions (self) {
  const opts = []
  if (self.global) opts.push('g')
  if (self.ignoreCase) opts.push('i')
  if (self.multiline) opts.push('m')
  return opts.join('')
}

RegExp.prototype.clone = function clone () {
  const self = this
  return new RegExp(self.source, getOptions(self))
}

RegExp.prototype.equals = function equals (other) {
  if (!(other instanceof RegExp)) return false
  const self = this
  return EJSON.stringify(self) === EJSON.stringify(other)
}

RegExp.prototype.typeName = function typeName () {
  return 'RegExp'
}

RegExp.prototype.toJSONValue = function toJSONValue () {
  const self = this
  return { regex: self.source, options: getOptions(self) }
}

EJSON.addType('RegExp', value => new RegExp(value.regex, value.options))

However, when extending the RegExp class and use this as EJSON-type then it works:

import { EJSON } from 'meteor/ejson'

function getOptions (self) {
  const opts = []
  if (self.global) opts.push('g')
  if (self.ignoreCase) opts.push('i')
  if (self.multiline) opts.push('m')
  return opts.join('')
}

class EJSONRegExp extends RegExp {
  clone () {
    const self = this
    return new RegExp(self.source, getOptions(self))
  }

  equals (other) {
    if (!(other instanceof RegExp)) return false
    const self = this
    return EJSON.stringify(self) === EJSON.stringify(other)
  }

  typeName () {
    return 'RegExp'
  }

  toJSONValue () {
    const self = this
    return {
      regex: self.source,
      options: getOptions(self)
    }
  }
}

EJSON.addType('RegExp', value => new RegExp(value.regex, value.options))

I have not 100% found out why/where this causes an issue but it must be in the DDP connection when stringifying the message contents and then checking for their types. :male_detective:

1 Like

That is not what I was talking about, but 100% qualifies as funky! Glad you figured it out