I've built this NodeJS server architecture 5 years ago. The project was in production all this time, I've been maintaining it actively, adding a lot of new features, and had no troubles with this architecture. So, now I have a budget to refactor it fundamentally. I'm considering if I should keep this architecture or move to the common REST architecture.
The project consists of a mobile app, web app, admin panel (also a web app), and a NodeJS server.
All 3 client-side parts are using Redux under the hood with socket.io sending actions with SOCKET/
prefix right to the server. The server accepts those actions and responds to them as many times as needed at any time.
I know where to improve the code, so, pls don't waste your time reviewing the code quality.
What I'm looking for is a review of this architecture. What are the downsides? Why I should use stateless REST instead of a stateful socket connection? Maybe it
I guess I'll omit the explanation of what are the pro-s of using this architecture for me, as it's not helpful in this context.
Probably, relevant info about this project:
- This is enterprise software that will never exceed 2-3 thousand active users.
- Vast majority of actions do not require real-time capabilities and would work just fine with question-answer model.
- At the moment we have ~600 active users and still using $24/month GCP instance.
Here is the essence:
import http from 'http'
import express from 'express'
import socketIo from 'socket.io'
import EventEmitter from './EventEmitter'
import actions from './actions'
const socket = async (server) => {
const io = socketIo(server)
const connectedUsers = new Map()
io.use(/*authorization middleware*/)
io.on('connection', async socket => {
const eventEmitter = new EventEmitter({ socket })
console.info(`=== v.${config.version} New connection ===`)
const sessionData = new Map()
sessionData.set('role', 'notLogedInUser')
sessionData.set('clientVersion', socket.authorizationData.clientVersion)
socket.emit('connected')
const emitAction = (actionType, actionPayload) => socket.emit('action', {
type: actionType,
payload: actionPayload
})
if (socket.authorizationData.authorized) {
const user = await db.users.findById(socket.authorizationData.userId)
sessionData.set('_id', user._id.toString())
// ...assigne other important user's props to sessionData
socket.on('action', async (action = {}) => {
const { type, payload } = action
if (!actions[type]) {
return emitAction('SNACK', 'Invalid action type')
}
actions[type]({
payload,
emitAction,
sessionData
})
})
} else {
emitAction('SNACK', 'Unauthorized')
}
socket.on('disconnect', () => {
console.info(`=== ${socket.id} has disconnected ===`)
connectedUsers.delete(socket.id)
})
})
}
let app = express()
app.server = https.createServer(app)
app.server.listen(config.port, '::', () => {
socket(app.server, config.port, config.hostname)
})
export default app
Thanks 🙏