Socket Error in Library Actions

Running a socket emit in a library action causes errors since 5.8.0:

ClientClosedError: The client is closed
    at Commander._RedisClient_sendCommand (/Users/tobi/dev/wpaas/node_modules/@redis/client/dist/lib/client/index.js:490:31)
    at Commander.commandsExecutor (/Users/tobi/dev/wpaas/node_modules/@redis/client/dist/lib/client/index.js:188:154)
    at Commander.BaseClass.<computed> [as publish] (/Users/tobi/dev/wpaas/node_modules/@redis/client/dist/lib/commander.js:8:29)
    at RedisAdapter.broadcast (/Users/tobi/dev/wpaas/node_modules/@socket.io/redis-adapter/dist/index.js:473:28)
    at BroadcastOperator.emit (/Users/tobi/dev/wpaas/node_modules/socket.io/dist/broadcast-operator.js:169:26)
    at App.exports.emit (/Users/tobi/dev/wpaas/lib/modules/sockets.js:20:42)
    at App._exec (/Users/tobi/dev/wpaas/lib/core/app.js:608:57)
    at App.exec (/Users/tobi/dev/wpaas/lib/core/app.js:544:20)
    at App._exec (/Users/tobi/dev/wpaas/lib/core/app.js:565:25)
    at async App._exec (/Users/tobi/dev/wpaas/lib/core/app.js:575:17)

Executing the socket emit directly in an API workflow works without issues. Running it via exec or include library action causes the above error.

The library action only contains a socket emit and nothing else.

@patrick

In lib/setup/sockets.js

 if (global.redisClient) {
       const { createAdapter } = require('@socket.io/redis-adapter');
       io.adapter(createAdapter(
        global.redisClient.duplicate(),
        global.redisClient.duplicate()
       ));
    }

global.redisClient.duplicate() was called immediately upon evaluating if (global.redisClient) . This caused an error when the client wasn’t fully connected before invoking the duplicate() method.

So changing that to

if (global.redisClient) {
    global.redisClient.on('connect', function() {
        const { createAdapter } = require('@socket.io/redis-adapter');
        const duplicateClient = global.redisClient.duplicate();
        io.adapter(createAdapter(global.redisClient, duplicateClient));
    });
}

Now it waits for the ‘connect’ event on the Redis client before creating the duplicate and setting up the adapter. This avoids the error by ensuring the client is fully connected before calling duplicate().

This fixed all the socket issues in 5.8 for me.

I applied this and as an FYI is not resolving the issues described here Debugging Issues with Websockets

I implemented it a little different, if the client was already connected the connect event is not triggered. Instead I call connect again on the duplicate client, it returns a promise which resolves when it is connected or resolved directly when already connected.

if (global.redisClient) {
    const { createAdapter } = require('@socket.io/redis-adapter');
    const pubClient = global.redisClient.duplicate();
    const subClient = global.redisClient.duplicate();

    Promise.all([pubClient.connect(), subClient.connect()]).then(() => {
        io.adapter(createAdapter(pubClient, subClient));
    });
}
2 Likes

Perfect, tested, and it works for me.

Fixed in Wappler 5.8.1

This topic was automatically closed after 46 hours. New replies are no longer allowed.