'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:
- Minimally-reproducible example
- Explanations of how you deployed to Cloud Run
- 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 |
