I'm developing a chat app where two users can talk to one another and I'm doing this with flask-socketio and React.
I've been struggling with trying to figure out this issue I'm getting with socket.io. Here's the error connection I keep getting once in a while on the browser console:
WebSocket connection to 'ws://127.0.0.1:5000/socket.io/?EIO=4&transport=websocket&sid=s8DKBembmWoxgGAsAAqX' failed: Insufficient resources
I'm having a difficult time trying to figure out what's causing this error. The way I solved this was to refresh the page and the connection is then re-established. I want to find a solution to this where I don't keep being disconnected from the socket and getting the same error message. Any idea on how to do this?
One common issue with sockets and react is how often you instantiate a WebSocket.
Incorrect usage of sockets in react
Here's an example of how it shouldn't be set up in a react component. Every time the component rerenders, a new socket will be set up, which will cause an Insufficient resources error.
import React, {useState} from 'react'
import { io } from "socket.io-client";
export default function MockSocket() {
const [message, setMessage] = useState("");
const socket = io();
socket.connect();
socket.on("recieve_message", setMessage);
return (
<div>
{message}
</div>
)
}
Correct usage of sockets in react
Instead, wrap the instantiation of WebSockets with a useEffect (such that it only triggers once, and is disconnected when the component is unmounted).
import React, {useEffect, useState} from 'react'
import { io } from "socket.io-client";
export default function MockSocket() {
const [message, setMessage] = useState("");
useEffect(
() => {
const socket = io();
socket.connect();
socket.on("recieve_message", setMessage);
return () => {
socket.disconnect();
}
},
[]
)
return (
<div>
{message}
</div>
)
}
Related
So, before I go deep in the problem let me explain you the basic of my app.
I have connection to DB(TypeOrm), Kafka(kafkajs) in my app.
My app is the Consumer of 1 topic which:
Gets some data in the callback handler, and puts that data in one table using TypeORM Entity
Maintains the Global map (in some Singleton Instance of a class) with some id (that I get in data of point 1).
At the time of app getting shutdown, my task is:
Disconnect all the consumers of the topics (this service is connected to) from the Kafka
Traverse the Global Map (point 2) and repark the message in the some topic
Disconnect the DB connections using the close method.
Here are some piece of code that might help you understand how I added the life cycle events on Server in NestJs.
system.server.life.cycle.events.ts
#Injectable()
export class SystemServerLifeCycleEventsShared implements BeforeApplicationShutdown {
constructor(#Inject(WINSTON_MODULE_PROVIDER) private readonly logger: Logger, private readonly someService: SomeService) {}
async beforeApplicationShutdown(signal: string) {
const [err] = await this.someService.handleAbruptEnding();
if (err) this.logger.info(`beforeApplicationShutdown, error::: ${JSON.stringify(err)}`);
this.logger.info(`beforeApplicationShutdown, signal ${signal}`);
}
}
some.service.ts
export class SomeService {
constructor(private readonly kafkaConnector: KafkaConnector, private readonly postgresConnector: PostgresConnector) {}
public async handleAbruptEnding(): Promise<any> {
await this.kafkaConnector.disconnectAllConsumers();
for(READ_FROM_GLOBAL_STORE) {
await this.kafkaConnector.function.call.to.repark.the.message();
}
await this.postgresConnector.disconnectAllConnections();
return true;
}
}
postgres.connector.ts
export class PostgresConnector {
private connectionManager: ConnectionManager;
constructor () {
this.connectionManager = getConnectionManager();
}
public async disconnectAllConnections(): Promise<void[]> {
const connectionClosePromises: Promise<void> = [];
connectionManager.connections?.forEach((connection) => {
if (connection.isConnected) connectionClosePromises.push(connection.close());
});
return Promise.all(connectionClosePromises);
}
}
ConnectionManager& getConnectionManager() imported from TypeORM module.
Now here are some unusual exceptions / behavior I am facing:
Disconnect all connections is throwing exception/error as in quote:
ERROR [TypeOrmModule] Cannot execute operation on "default" connection because connection is not yet established.
If connection is not yet established then how come my isConnected came true inside of if. I am not getting any clue anywhere how is this possible. And how to do graceful shutdown of the connection in TypeORM.
Do we really need to handle the closure of the connection in TypeORM or it internally handles it.
Even if, TypeORM handles the connection closure internally, how could we achieve it explicitly.
Is there any callback that can be triggered in case the connection is disconnected properly so that I am sure, that disconnection actually happened from the db.
Some of the messages are coming after I press CTRL + C (mimicking the abrupt/closure of the process of my server) and the control comes back to Terminal. This means, some thread is coming back after the handle returns to my terminal (🤷, no clue, how would I handle this, since if you see, my handleAbruptHandling is awaited and also, I cross checked all the promises are being awaited properly.)
Some of the things to know:
I properly added my module to create the hooks of server life cycle events.
Injected the objects in almost all the classes properly.
Not getting any DI issue from NEST and server is getting started properly.
Please shed some light and let me know how can I gracefully disconnect from db using typeorm api inside NestJs in case of abrupt closure.
Thanks in advance and happy coding :)
Littlebit late but may help someone..
You are missing the param keepConnectionAlive as true in TypeOrmModuleOptions, typeOrm dont keep connections alive as default. I set keepConnectionAlive as false, if a transaction keeps the connection open im going to close the connection (typeorm wait until the transaction or other process finish before close the connection), this is my implementation
import { Logger, Injectable, OnApplicationShutdown } from '#nestjs/common';
import { getConnectionManager } from 'typeorm';
#Injectable()
export class LifecyclesService implements OnApplicationShutdown {
private readonly logger = new Logger();
onApplicationShutdown(signal: string) {
this.logger.warn('SIGNTERM: ', signal);
this.closeDBConnection();
}
closeDBConnection() {
const conn = getConnectionManager().get();
if (conn.isConnected) {
conn
.close()
.then(() => {
this.logger.log('DB conn closed');
})
.catch((err: any) => {
this.logger.error('Error clossing conn to DB, ', err);
});
} else {
this.logger.log('DB conn already closed.');
}
}
}
I discovered some TypeORM docs saying "Disconnection (closing all connections in the pool) is made when close is called"
Here: https://typeorm.biunav.com/en/connection.html#what-is-connection
I tried export const AppDataSource = new DataSource({ // details }) and importing it and doing
import { AppDataSource } from "../../src/db/data-source";
function closeConnection() {
console.log("Closing connection to db");
// AppDataSource.close(); // said "deprecated - use destroy() instead"
AppDataSource.destroy(); // hence I did this
}
export default closeConnection;
Maybe this will save someone some time
After migration from Mobx 5 to Mobx 6 for some unknown reason, components stopped rerendering when router path is changed. routerStore5 seems like its not observable even if its decorated by it. State inside routerStore5 is changing, but components dont react for this state change. In Mobx 5 it worked fine but in new Mobx it does not. Is there some problem with package compatibility?
this connect is used as decorator for components which should have access to Mobx store
export function componentConnect(target) {
return inject('stores')(withTheme(observer(target)));
}
Router store is accessible via connect above
export class RouterStore {
#observable routerStore5: RouterStore5;
constructor() {
const routerStore = new RouterStore5();
const router = createRouter(routes, {
defaultRoute: 'home',
queryParamsMode: 'loose'
});
router.usePlugin(mobxPlugin(routerStore));
router.usePlugin(browserPlugin({ useHash: false }));
makeObservable(this);
this.routerStore5 = routerStore;
this.routerStore5.router.start();
}
}
Here is list of used npm packages:
"router5": "^8.0.1",
"router5-plugin-browser": "^8.0.1",
"react-router5": "^8.0.1",
"mobx": "^6.1.8",
"mobx-react": "^7.1.0",
"mobx-router5": "^4.3.0",
"mobx-utils": "^6.0.3",
Ok, guys, here's the problem... I've been writing code for my web application using another fluently working app as an example for the beginning. Here is the source code:
(./app.jsx)
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import { Router, Route, IndexRoute, browserHistory } from 'react-router';
import App from './components/app';
import Signin from './components/auth/signin';
import reducers from './reducers';
const createStoreWithMiddleware = applyMiddleware()(createStore);
ReactDOM.render(
<Provider store={createStoreWithMiddleware(reducers)}>
<Router history={browserHistory}>
<Route path='/' component={App}>
<Route path='signin' component={Signin} />
</Route>
</Router>
</Provider>,
document.getElementById('app')
);
(./components/app.js)
import React, { Component } from 'react';
import Header from './header';
export default class App extends Component {
render() {
return (
<div>
<Header />
{this.props.children}
</div>
);
}
}
(./components/auth/signing.js)
import React, { Component } from 'react';
import { reduxForm } from 'redux-form';
class Signin extends Component {
handleFormSubmit({ email, password }) {
console.log(email, password);
}
render() {
const { handleSubmit, fields: { email, password }} = this.props;
return (
<form onSubmit={handleSubmit(this.handleFormSubmit.bind(this))}>
<fieldset className="form-group">
<label>Email</label>
<input {...email} className="form-control"/ >
</fieldset>
<fieldset className="form-group">
<label>Email</label>
<input {...password} className="form-control"/ >
</fieldset>
<button action="submit" className="btn btn-primary">Sign in</button>
</form>
);
}
}
export default reduxForm({
form: 'signin',
fields: ['email', 'password']
})(Signin);
(you can see my whole repository here: https://github.com/LiJuons/react-dribbble )
The thing is that when I go to localhost:3000 - everything's Ok, but when I enter localhost:3000/signin - I get error message that says "Cannot GET /signin" THOUGH the application I'm taking code from works properly and shows form!
The problem is in routes, because if I set signin.js route's path to '/' in my project, form is shown on home directory without any problem.
Package.json files are the same in both projects (same number of packages, same versions and dependencies), only start script differs, so...
THE ONLY DIFFERENCE between the working project and mine is that in working one 'npm start' script is defined as:
"start": "node ./node_modules/webpack-dev-server/bin/webpack-dev-server.js"
where in mine it's:
"start": "node server.js"
P.S. I checked every line to be sure that code of both projects would be as homogeneous as possible.
Any suggestions how to fix this issue?
Thank you
Your server is probably not configured to support HTML5 history.
Take a look at https://medium.com/#baphemot/understanding-react-deployment-5a717d4378fd
React-router not working when typing URLÂ manually
This is a common surprise and is related to the fact that you are using browserHistory in your application, which requires some additional configuration of the server itself. Basically, when you type the URL by hand, by default the server will look for a file with that path, stored on its disk — if not found, it will show a 404 error. What you want to do is internally redirect the request to the index of your application.
You can see the documentation for react-router v3 about this setting (don’t worry, it’s still valid for react-router 4!). Common configuration are:
express:
const express = require('express')
const path = require('path')
const port = process.env.PORT || 8080
const app = express()
// this assumes that all your app files
// `public` directory relative to where your server.js is
app.use(express.static(__dirname + '/public'))
app.get('*', function (request, response){
response.sendFile(path.resolve(__dirname, 'public', 'index.html'))
})
app.listen(port)
console.log("Server started on port " + port);
I have an app that needs to check with a backend API before rendering 404. The routing flow works something like this:
Request comes in to /{INCOMING_PATH}, and the application attempts to fetch and render data from api.com/pages/{INCOMING_PATH}.
If the API returns 404, then the app should return 404. If not, the data is rendered.
I'm not sold on using for this use case. {INCOMING_PATH} will be dynamic, potentially with slashes and extensions in the path. Is this possible to implement in React Router (with proper SSR behavior too)? If so, how should I proceed?
(This question was originally posted on github by another user. They were requested to post it here as it is a support request. But it doesn't seem they did. I am now stuck on exactly the same issue.)
I've solved this with the React Nested Status module.
I'm using https://github.com/erikras/react-redux-universal-hot-example so this code is geared towards that. See React Nested Status for a more generic solution.
Edits to server.js:
at the top
import NestedStatus from 'react-nested-status';
at the bottom replace:
const status = getStatusFromRoutes(routerState.routes);
if (status) {
res.status(status);
}
res.send('<!doctype html>\n' +
ReactDOM.renderToString(<Html assets={webpackIsomorphicTools.assets()} component={component} store={store}/>));
with:
const repsonse = ReactDOM.renderToString(
<Html assets={webpackIsomorphicTools.assets()} component={component} store={store}/>
);
const status = getStatusFromRoutes(routerState.routes);
if (status) {
res.status(status);
}
const nestedStatus = NestedStatus.rewind();
if (nestedStatus !== 200) {
res.status(nestedStatus);
}
res.send('<!doctype html>\n' + repsonse);
Then in what ever container/component you need to serve a 404 :
import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import connectData from 'helpers/connectData';
import { fetchApiData } from 'redux/modules/foo/fetchApiData';
import { NotFound } from 'containers';
#connectData(null, (getReduxState, dispatch, state, params) => {
return dispatch(fetchApiData(params.fooId));
})
#connect(
(reduxState) => ({
fooData: reduxState.foo.data,
})
)
export default class ProductType extends Component {
static propTypes = {
fooData: PropTypes.object,
}
render() {
let content;
// ... whatever your api sends back to indicate this is a 404
if (!this.props.fooData.exists) {
content = <NotFound/>;
} else {
content = (
<div className={styles.productType}>
Normal content...
</div>
);
}
return content;
}
}
Finally replace /src/containers/NotFound/NotFound.js
import React, { Component } from 'react';
import NestedStatus from 'react-nested-status';
export default class NotFound extends Component {
render() {
return (
<NestedStatus code={404}>
<div className="container">
<h1>Error 404! Page not found.</h1>
</div>
</NestedStatus>
);
}
}
I'm not sure what kind of state implementation you are using. But, if you are using redux, then I think the simplest way is to use redux-simple-router. With it, your Routes are synchronized within your state, so you can dispatch action creators to change the router path. I would try to update satate with action creators instead of pushing the state directly from a component. The truth point must be always the state, in your case I would act as follows:
The component that requires to fetch the data will be subscribed to the "dataReducer" which is the isolated state part that this component should care about. Maybe the initial state of dataReducer is an empty array. Then, in componentWillMount you dispatch an action like: dispatch(fetchDataFromApi)) If the response code is 404, then in the action fetchDataFromApi you can dispatch another action, that is just an object like this one:
{type:SET_NOT_FOUND_ERROR}
That action will be handled by the reducer dataReducer, and will return a new state with an object (consider Immutability) that will have a property error, which will be a string with the reason, or whatever you want.
Then, in componentWillReceiveProps method, you, can check if the nextProps have or not have an error. If Error, you can render your error component, or even dispatch an action to go to the error page handled by react-router.
If no error, then you can dispatch an action (thanks to redux-simple-router) to go to the path y
I'm attempting to use Marty v0.10 and React Router v1.0.0. The example React Router provides doesn't seem to allow wrapping a handler in the application container. React Router says to use React.render as opposed to Router.run. The only example of Router.run is on the server side.
My implementation from marty.js v0.10 and React Router v0.13 throws the following error:
Invariant Violation: Router.run needs a callback
This is due to Router.run now expecting 3 parameters. I'm not sure what the second parameter should be in the browser.
Any tips on getting this:
Router.run(routes, (Handler, state) => {
React.render(
<ApplicationContainer app={ application }>
<Handler { ...state.params } />
</ApplicationContainer>,
document.body
);
});
to work with Rect Router 1.0.0 beta?
Obvious question is obvious.
Just throw the render logic into React.render.
React.render(
<ApplicationContainer app={ application }>
{ routes }
</ApplicationContainer>
, document.body
);