Redux-saga and socket subscription causes Uncaught TypeError: Converting circular structure to JSON

338 Views Asked by At

I am having trouble subscribing to a socketcluster (http://socketcluster.io/) channel when using a redux-saga generator in my chat app. The socketcluster backend is setup in a way where any messages are saved in the database then published into the receiving user's personal channel, which is named after the user's id. For example, User A has an id '123abc' and would subscribe to the channel named '123abc' for their realtime messages.

The code below does receive new messages that are published to a channel but it throws a "TypeError: Converting circular structure to JSON" onload and breaks all of my other redux-saga generators in the app. I've done digging in Chrome Devtools and my theory is that it has something to do with queue created in the createChannel function. Also, I've tried returning a deferred promise in the subscribeToChannel function but that also caused a Circular Conversion Error, I can post that code on request.

I referred to this answer at first: https://stackoverflow.com/a/35288877/5068616 and it helped me get the below code in place but I cannot find any similar issues on the internet. Also something to note, I am utilizing redux-socket-cluster (https://github.com/mattkrick/redux-socket-cluster) to sync up the socket and state, but I don't think it is the root of the problem

sagas.js

export default function* root() {
    yield [
        fork(startSubscription),
    ]
}


function* startSubscription(getState) {
    while (true) {
        const {
            userId
        } = yield take(actions.SUBSCRIBE_TO_MY_CHANNEL);
        yield call(monitorChangeEvents, subscribeToChannel(userId))
    }
}

function* monitorChangeEvents(channel) {
    while (true) {
        const info = yield call(channel.take) // Blocks until the promise resolves
        console.log(info)
    }
}

function subscribeToChannel(channelName) {
    const channel = createChannel();
    const socket = socketCluster.connect(socketConfig);
    const c = socket.subscribe(channelName);
    c.watch(event => {
        channel.put(event)
    })

    return channel;
}

function createChannel() {
    const messageQueue = []
    const resolveQueue = []

    function put(msg) {
        // anyone waiting for a message ?
        if (resolveQueue.length) {
            // deliver the message to the oldest one waiting (First In First Out)
            const nextResolve = resolveQueue.shift()
            nextResolve(msg)
        } else {
            // no one is waiting ? queue the event
            messageQueue.push(msg)
        }
    }

    // returns a Promise resolved with the next message
    function take() {
        // do we have queued messages ?
        if (messageQueue.length) {
            // deliver the oldest queued message
            return Promise.resolve(messageQueue.shift())
        } else {
            // no queued messages ? queue the taker until a message arrives
            return new Promise((resolve) => resolveQueue.push(resolve))
        }
    }

    return {
        take,
        put
    }
}

Thanks for the help!

0

There are 0 best solutions below