-
-
Notifications
You must be signed in to change notification settings - Fork 7.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ConnectedSocket DI scope for services running under WebSocketGateway #4287
Comments
To overcome current limitations for WebSocketGateway, I am forced to use my own "twisted dependency injection" mechanics, creating or passing instances of providers inside handleConnection, and performing cleanup on handleDisconnect. This way if I want ConnectedSocket scoped providers - i instantiate them in handleConnection, while if i want to have a global injected providers, I provide them inside class constructor and pass down inside handleConnection. |
This makes a lot of sense, and would be in line with the usual (connection scoped) socket.io handling |
Would anyone here have advice as to how to make this workaround work when using GraphQL subscriptions? Does this use a |
@flux627 I don't think there is a way to do this using standard Dependency Injection mechanics. The closest I could get (As described in the screenshot above) is the following:
This approach adds extra code, but allows to utilize DI override mecanics. As for "context", you can store everything inside websocketClient passed in as first argument to onConnect/onDisconnect. Everything attached to that client would be connection-based, you can also pass the client itself to other classes to provide access to that context to other classes. I got to admit, it looks ugly, but it works. |
Almost two years passed since the issue was created, I couldn't find the way back then and set the task aside. But now that I got back to it, I found a way to achieve the desired using WebsocketGateway and module refs. Simply:
Caution: WebsocketGateway should not use any connection-scoped providers, DI-logic starts from ConnectionGateway. As for the original feature request, now that I had a little thought about it, I believe that instead of adding new ConnectedSocket DI scope for WebSocketGateway, the Request scope should be reused to match connection. Having REQUEST scope binding to webSocket messages is a huge overhead, the typical websockets communication include hundreds of messages going in and out for every client. The only problem is that it would introduce a breaking change, and there could be people out there already using message based REQUEST scope for web sockets. |
I think this would be a great feature... According to this comment it is not being pursued. Does anyone know why? |
The problem is probably around a conflict between scopes and singularity of socket server. One of the requested feature - is to be able to inject the single server into other providers. Rewriting that in a simple provider mannor would require having a ubiquitous provider that is both available as singleton and request-scoped. Not much can be done at this point, all the choices are heavy:
Both roads are a NO, for a stable framework. The only viable solution would be deprecating Adding a WebConnectionGateway could probably be done in a community package. Or as an alternative, you can easily achieve the same result with a few lines of code (via @Injectable()
export class ScopedConnectionInjector {
constructor(private readonly moduleRef: ModuleRef) { }
async register(socket: SocketIO.Socket) {
(socket as any)[REQUEST_CONTEXT_ID] = ContextIdFactory.create();
const connection = await this.getConnectionGateway(socket);
connection.setConnection(socket);
}
async getConnectionGateway(socket: SocketIO.Socket) {
const contextId = (socket as any)[REQUEST_CONTEXT_ID];
return this.moduleRef.resolve(ConnectionGateway, contextId);
}
} Where |
Feature Request
Add a ConnectedSocket scope for injectables.
Is your feature request related to a problem? Please describe.
There are currently 3 types of scopes:
That works well for normal http requests, but for websockets, request scope is not a thing according to docs:
WebSocket service design is built upon the idea that you have a "connection" which is a lot similar to a session or request, all the data transferred between connect and disconnect is usually treated as a single scope.
Out of all available mechanics to persist that data, we have @ConnectedSocket, which is only accessible from WebSocketGateway, so without a built in support for ConnectedSocket scope, we are forced to implement our own storages within socket and pass socket around in all the calls made between WebSocketGateway and services, which is exactly why Scopes.REQUEST was initially introduced in http.
Describe the solution you'd like
Add a new ConnectedSocket scope applicable to services that would create a new instance of a provider for each connection, within such services there is a need to access current socket client same way
@Request
decorator does for request-scope.As far as I understand the problem lies within the fact that we must not generate new
WebSocketGateway
for connections, thus the propagation mechanics of Scopes break apart. But isn't@ConnectedSocket
already enforcing similar breaches? As in, it is available withinWebWocketGateway
, but it is running within it's own virtual "scope".Teachability, Documentation, Adoption, Migration Strategy
What is the motivation / use case for changing the behaviour?
Enforce similar system design on WebSockets as the already existing request within http eco-system to solve all the same troubles but within WebSocket context.
In addition, this would allow creating proper facades for Socket client to not call emit directly with no event/data type-checking.
The text was updated successfully, but these errors were encountered: