                     #console.log("changefeed #{@_table} produced: #{err}, ", resp)
                     # changefeed
                     if err
-                        # TODO: test this by disconnecting backend database
-                        console.warn("query #{@_table}: _run: not first error ", err)
+                        @_connected = false
+                        if err != 'killfeed'    # killfeed is expected and happens regularly (right now)
+                            console.warn("query #{@_table}: _run: not first error -- ", err)
                         @_reconnect()
                     else
                         @_update_change(resp)

        # Is anonymous access to this table allowed?
        @_anonymous = !!@_schema.anonymous

    _reconnect: (cb) =>
        if @_closed
            throw Error("object is closed")
        if not @_anonymous and not @_client.is_signed_in()
            #console.log("waiting for sign in before connecting")
            @_client.once 'signed_in', =>
                #console.log("sign in triggered connecting")
                @_reconnect(cb)
            return
        if @_reconnecting?
            @_reconnecting.push(cb)
            return
        @_reconnecting = [cb]
        connect = false
        async.series([
            (cb) =>
                if not @_id?
                    connect = true
                    cb()
                else
                    # TODO: this should be done better via registering in client, which also needs to
                    # *cancel* any old changefeeds we don't care about, e.g., due
                    # to refreshing browser, but are still getting messages about.
                    @_client.query_get_changefeed_ids
                        cb : (err, ids) =>
                            if err or @_id not in ids
                                connect = true
                            cb()
            (cb) =>
                if connect
                    misc.retry_until_success
                        f           : @_run
                        start_delay : 1500
                        factor      : 1.3
                        max_delay   : 60000       # expontial backoff up to 60 seconds
                        max_time    : 1000*60*10  # give up completely after 10 minutes
                        cb          : cb
                else
                    cb()
        ], (err) =>
            if err
                @emit("error", err)
            v = @_reconnecting
            delete @_reconnecting
            for cb in v
                cb?(err)
        )

    _run: (cb) =>
        if @_closed
            throw Error("object is closed")
        first = true
        #console.log("query #{@_table}: _run")
        @_client.query
            query   : @_query

            options : @_options
            cb      : (err, resp) =>
                @_last_err = err
                #console.log("query #{@_table}: -- got result of doing query", resp)
                if first_resp
                    first_resp = false
                    if @_closed
                        cb?("closed")
                    else if err
                        console.warn("query #{@_table}: _run: first error ", err)
                        cb?(err)
                    else if not resp?.query?[@_table]?
                        console.warn("query on #{@_table} returned undefined")
                        cb?("got no data")
                    else
                        @_id = resp.id
                        @_connected = true
                        #console.log("query #{@_table}: query resp = ", resp)
                        @_update_all(resp.query[@_table])
                        cb?()
