'can't socket.emit() in Cloud Run server environment

My site is using socket.io. Locally it works great. But after deploying with gcloud run deploy the socket.emit() in my javascript file, wont communicate with my app.js file/server.

js file

socket.emit("connectedforrecording");

app.js file

function newConnection(socket) {
    
    console.log("Connection with ID: " + socket.id);
    
    socket.on("connectedforrecording", () => {
        console.log("anything??")
        // here are connections from /new
        console.log("record page",  socket.id);
        let tempDir ="./tempDirs/temp"+socket.id;
        fs.mkdir(tempDir, () => {
            fs.chmod(tempDir, "777", () =>{console.log("chmod", tempDir);});
            console.log(tempDir);}); // temp dirextory for audio files
        var audioReceived = 0;//this flags if writing/written to canvas, so directory is not deleted!
        let start = Math.floor(Math.random()*(canvasSize-30)); //start position for recording in secs
        console.log(start);
        let userdetailsrecieved = 0;
        let userDetails = {index: 0, start:0, name:"anonymous", link:"", freq:1000, colour: "#EF863F", sharpness:0.5, sentence:""}; // create a json object with default numbers
        userDetails.start = start; // add attribute: start
        // request sound from server
        socket.on("requestSound", ()=>{
            socket.emit("flag", start); // sends start pos to client 
            sendCanvasSection("./canvas.raw", start, socket);
            //////////////////////////////////////n.b. !!!!
            //          let s = tools.sentence();
            let s = sentence();
            console.log(s);
            console.log("color: ", s.colour);
            socket.emit("sentence", s);
            //          userDetails.colour = {"r":parseInt(hex.slice(1,3), 16), "g":parseInt(hex.slice(3,5), 16), "b":parseInt(hex.slice(5,7), 16)};
            userDetails.colour = hexToRgb(s.colour[0]);
            userDetails.sharpness = 1- s.angle.v;
            userDetails.sentence = s.sentence;
            console.log(userDetails);
        });
        

        });
    });
}


Solution 1:[1]

Your question is difficult to answer because you're missing important components of your solution:

  1. Minimally-reproducible example
  2. Explanations of how you deployed to Cloud Run
  3. What you observed, logs and other output

Arbitrary code deployed to Cloud Run cannot be expected to run.

In fact, there's a Cloud Run contract to which code must adhere.

Principally (!), Cloud Run requires a server that listen on (whatever value but generally 8080) is assigned to the PORT environment variable.

WebSockets can be used with Cloud Run services.

Cloud Run provides an in-memory file system (see link) and so you can use Node's fs and can use e.g. fs.mkdir.

Here's my minimally-repro example of a WebSockets solution on Cloud Run that summarizes my attempt to answer your question. I mashed-up Google's WebSockets sample and the intro from Socket.IO

BILLING="[[YOUR-BILLING-ACCOUNT]]"
PROJECT="[[YOUR-PROJECT-ID]]"
REGION="[[YOUR-REGION]]" # e.g. "us-west1"
NAME="[[YOUR-SERVICE]]" # e.g. "websockets"

SERVICES="artifactregistry cloudbuild run"
for SERVICE in ${SERVICES}
do
  gcloud services enable ${SERVICE}.googleapis.com \
  --project=${PROJECT}
done

gcloud beta run deploy ${NAME} \
--source . \
--allow-unauthenticated \
--region=${REGION} \
--project=${PROJECT} \
--timeout 3600

# Browse
ENDPOINT=$(\
  gcloud beta run services describe ${NAME} \
  --project=${PROJECT} \
  --region=${REGION} \
  --format="value(status.url)")
curl --request GET ${ENDPOINT}

I was lazy, the only output is in the client's developer console logs and the server's logs:

FILTER="
resource.type = \"cloud_run_revision\"
resource.labels.service_name = \"${NAME}\"
resource.labels.location = \"${REGION}\"
"

gcloud logging read "${FILTER}" \
--project=${PROJECT} \
--format="value(textPayload)"

Yields:

Listening on 8080
[./tempDirs/templDX9eww0pDOpN63JAAAB] entered
[./tempDirs/templDX9eww0pDOpN63JAAAB] done
[./tempDirs/templDX9eww0pDOpN63JAAAB] chmod
hello from client: 5,6,[object Object]

And the code:

package.json:

{
    "name": "websockets",
    "version": "0.0.1",
    "scripts": {
      "start": "node index.js"
    },
    "dependencies": {
      "express": "^4.17.3",
      "socket.io": "^4.4.1"
    }
  }
}

index.js:

// Use server.js
const server = require('./server');

// Cloud Run contract requires server on PORT (or 8080)
const PORT = parseInt(process.env.PORT) || 8080;

server.listen(PORT, () =>
  console.log(`Listening on ${PORT}`)
);

process.on('SIGTERM', () => {
  process.exit(0);
});

module.exports = server;

server.js:

const express = require('express');
const fs = require('fs')

const app = express();
app.use(express.static(__dirname + '/'));

app.get('/', async (req, res) => {
  res.render('index');
});

const server = require('http').Server(app);
const io = require('socket.io')(server);

io.on('connection', socket => {
    socket.emit("hello from server", 1, "2", { 3: Buffer.from([4]) });

    // Proof of fs
    // From your code
    let tempDir ="./tempDirs/temp"+socket.id;
    fs.mkdir(tempDir, () => {
        console.log(`[${tempDir}] entered`);
        fs.chmod(tempDir, "777", () =>{
          console.log(`[${tempDir}] chmod`);
        });
        console.log(`[${tempDir}] done`);
    });

    socket.on("hello from client", (...args) => {
        console.log(`hello from client: ${args}`);
    });
});

module.exports = server;

index.html:

<html>
<head></head>
<body></body>
<script src="/socket.io/socket.io.js"></script>
<script>
const socket = io("", {
  transports: ["websocket"],
});

socket.emit("hello from client", 5, "6", { 7: Uint8Array.from([8]) });

socket.on("hello from server", (...args) => {
  console.log(`hello from server: ${args}`);
});    
</script>
</html>

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1