                                         # or try to be even more clever in various ways.  However, all approaches along
                                         # those lines involve manipulating complicated data structures in the server
                                         # that could take too much cpu time or memory.  So we go with this simple solution.
-                                        @table('projects').wait(waitFor: "ready_for_writes", timeout:30).run (err) =>
-                                            if err
-                                                cb(err)
-                                            else
-                                                @table('projects').getAll(opts.account_id, index:'users').pluck('users').changes(includeStates: false, squash:5).run (err, feed) =>
-                                                    if err
-                                                        e = misc.to_json(err)
-                                                        if e.indexOf("Did you just reshard?") != -1
-                                                            # give it time so we do not overload the server
-                                                            setTimeout((()=>cb(err)), 10000)
+                                        @wait_until_ready_for_writes
+                                            table : 'projects'
+                                            cb    : (err) =>
+                                                if err
+                                                    cb(err)
+                                                else
+                                                    @table('projects').getAll(opts.account_id, index:'users').pluck('users').changes(includeStates: false, squash:5).run (err, feed) =>
+                                                        if err
+                                                            e = misc.to_json(err)
+                                                            if e.indexOf("Did you just reshard?") != -1
+                                                                # give it time so we do not overload the server
+                                                                setTimeout((()=>cb(err)), 10000)
+                                                            else
+                                                                cb(err)
                                                         else
-                                                            cb(err)
-                                                    else
-                                                        killfeed = feed
-                                                        cb()
+                                                            killfeed = feed
+                                                            cb()
                                     else
                                         cb()
                     else if typeof(x) == 'function'

                ## cb(); return # to disable
                if opts.changes
                    # see discussion at https://github.com/rethinkdb/rethinkdb/issues/4754#issuecomment-143477039
                    db_query.wait(waitFor: "ready_for_writes", timeout:30).run(cb)
                else
                    cb()
            (cb) =>

            query = query.union(db.table(opts.tables[i]))
        query.changes(includeInitial:false).run (err, feed) =>
            feed.each(opts.cb)

    # Wait until the table is ready for queries.
    # NOTE:
    wait_until_ready_for_writes: (opts) =>
        opts = defaults opts,
            table     : required     # string -- name of a table
            timeout_s : 30
            cache     : true         # if true, cache success for 10s; this is more efficient, but means SMC will stop responding properly during a failure for a few seconds.
            cb        : required     # cb(undefined, obj) on success and cb('timeout') on failure due to timeout
        last = (@_wait_until_ready_for_writes_last ?= {})
        if opts.cache and (last[opts.table]? and new Date() - last[opts.table] < 10000)
            opts.cb()
            return
        d = (@_wait_until_ready_for_writes ?= {})
        if not d[opts.table]?
            d[opts.table] = [opts.cb]
        else
            d[opts.table].push(opts.cb)
            return
        @table(opts.table).wait(waitFor: "ready_for_writes", timeout:30).run (err) =>
            if not err and opts.cache
                last[opts.table] = new Date()
            for cb in d[opts.table]
                cb(err)
            delete d[opts.table]

    # Wait until the query results in at least one result obj, and
    # calls cb(undefined, obj).
