-
Notifications
You must be signed in to change notification settings - Fork 1.9k
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
Define HttpSession behaviors during WebSocket LifeCycle #3981
Comments
Just to add some info on this issue wrt changes for #3913: I can confirm that the HttpSession is still usable during the point in time the websocket is being established (specifically I tested accessing the HttpSession during the call to Configurator.modifyHandshake). Thus, our current recommended solution of accessing the session and retrieving all values you want to use from it is still valid post #3913 changes. |
I have a question (which I think is relevant in this context--and hopefully for others that might be searching for answers). Joakim assembled an excellent set of questions. My perception is that the standards did not keep pace with the needs of developers in this particular instance. So, with that in mind... is there a recommended approach for developers who need to build a Jetty server to share server state between normal "REST" type of servlets and web sockets? How are people solving this today? My initial thought is:
I haven't thought through all of the implications (e.g. session ID that changes); but I wanted to get an expert opinion. Would you go down this track? Do something else? I greatly appreciate your time and Jetty! -Robert |
A common pattern that has emerged is that the application controls it's server state tracking in a way that doesn't rely on servlet HttpSession. (this works for REST, WebSocket, grpc, etc...) HTTP uses Cookie to set an application state tracking id of it's own. The HTTP State is obtained from this cookie id. There are many libs for Java available to do this already. |
I don't know of any other libraries (besides Spring, which I'm not using) From my perspective we've already taken on some technical debt in order to support HttpSessions (session handler, session cache, and a persistence layer, and more!) -- so logically I'm wondering why wouldn't we re-use some of this investment? The session mostly does what I need (store a bit of data). In concrete terms for Jetty, is there any reason you would advise against simply passing a reference to my servlet environment's instance of Edit: seems I would need to pass my |
The thing is, WebSocket is not HTTP. (It's websocket) It just so happens that one way to initiate WebSocket on HTTP/1.1 using the HTTP upgrade process. The only point in time where HTTP is involved in WebSocket is during the upgrade request. Expecting |
I understand. But just because it's named "HttpSession", does that disqualify it from being used in a more general sense to store small pieces of connection / user related information for websocket? These are the things I like about existing (yes "HTTP" sessions...):
And...
So why would I throw all of that away and start from scratch just because I'm in a WebSocket? That doesn't make any sense to me. Why wouldn't we generalize Session to be a more abstract concept that can be used regardless of protocol? |
You know that Why? Well, that's because at it's heart websocket is not HTTP and is not connected to the Servlet spec. The only safe thing for you is to access what you need from the Now lets talk about your points ...
If you have a client that starts with a WebSocket (no prior HTTP calls), this fails.
WebSocket upgrade will never create a client cookie (it cannot, and most browsers will reject Set-Cookie headers seen during any HTTP upgrade).
Depending on your choice of WebSocket technology, authentication is not applied during WebSocket upgrade.
Only POJOs that are properly written to allow serialization.
For WebSocket, this would require your clustering solution to push changes into long lived HttpSession object instances being held by WebSocket endpoints.
Actions of HTTP Session HouseKeeper have no impact on active WebSocket connections.
This layer was created for HTTP, using HTTP concepts, to help with short-lived request/response exchanges (eg: HTTP), never for long duration connections. There's a reason why in the past 11 years (WebSocket is that old now) more and more groups have been moving away from relying on HttpSession, as the technologies around the web increase to be more and more non-HTTP. The old concepts built around HTTP no longer serve the greater needs of the modern complex multi-protocol application (your use of WebSocket makes your application now a multi-protocol application). If you look at most modern libraries that support both Servlet and WebSocket you'll quickly see that the work is being done by the library for auth / security / state, not the container or the servlet spec anymore. (spark has it's own layers for auth/state, spring too, google cloud as well, along with many many others). |
You fill your posts with information / facts; but you've completely missed the heart of the discussion. Sessions are useful. In my usage of Jetty I use them today. I want to share that state with Websockets--and have Websockets contribute / modify that state. How would you do it? You've waved your hands at "other libraries" but you've failed tell me simply: what would you do? What would you recommend Jetty users do? And it seems to me your answer is: start from scratch. |
The overwhelming majority of Servlet + WebSocket (Jetty and Tomcat) users that need data from the HttpSession object have the following behaviors and restrictions. (Pointed out this in a previous message already, so I'm stating it again, but in a different way)
I know I sound like a broken record, but I've tried to point out how HttpSession fits into the world of servlets and Jakarta EE. We, Jetty, cannot invent this for just Jetty, as the minute we do we break other specs that have defined behaviors around HttpSession, and greatly complicate the entire HttpSession layer for all usages to attempt to support it. |
When this issue was created, we were discussing with other specs in Jakarta EE to see if a solution could be found. |
@rfox12 Sorry that the answer to you appartently simple question is so complex. To answer your question "What would you recommend Jetty users do" is to avoid trying to use sessions as a distributed database. Their semantics is so poorly defined that it is hard to keep them coherent with updates from simultaneous requests to the same node, let alone if you add in distributed nodes and/or other protocols. Sessions can be useful is storing immutable keys to other data, or perhaps a cache of read-only data (or snapshot) taken from a database. But they are not suitable for general purpose distributed/concurrent storage of rich mutable objects. Websocket end-points only have a relationship with a HttpSession as they are created. Other than that, websockets cannot influence sessions in any way to: a) keep them resident in memory; b) mark them as dirty so that mutations are written out; c) touch them so that they do not timeout. So my reecommendation is that if you have distributed data, then put it in a proper distributed database form which there are many to choose from. By all means put keys and or cached copies of data in your HttpSession, but don't try to mutate that and expect any coherent results... even on a single node. If your session data is like that, then your websocket end-points can also grab copies of those keys and/or caches from the session as they are created. But they need to interact directly with the real distributed database if you wish to do any mutations. Having said all that, there are users that do get away with accessing session from websocket endpoints via references. It may be that their session datastore and/or session cache are configured in such a way that the access patterns work. It may be that there is enough HTTP traffic along side the websocket to keep the session alive. It may be that they mutations of session data jsut happen to be safe or fail so infrequently that it is not noticeable. So there may well be some specific circumstances under which you can do a lot better than "start from scratch". But in general we don't recommend using sessions for mutable data. Yes it is a sorry state of affairs. Sessions suck! |
This is informative.
Indeed. I have one--namely MongoDB. Thank you both for your responses. I didn't mean to come off as belligerent; I was simply / honestly trying to see if there was some expert-recommended path. Where there is a will there is a way; and in the space of a couple of days I can hack around these issues. Here is my tentative plan (for what it's worth...)
I will have to read some more code; but as far as I can tell the parts that I want to use are thread safe. Small side note: I'm somewhat surprised that the I don't expect you to condone this. Others are certainly solving for this in their own ways. I do not envy the "standards bearers" of legacy J2EE. I think I've taken enough of your time (thank you!). Last note: I encourage you to lead with regards to meeting the needs of developers. Over the 25 years I've been hacking I've noticed that solutions that adhere to standards weren't the ones that won. It was the solutions that met developer needs that won out. Maybe it's better that sessions are out of scope in Jetty? Maybe there is a smart way to incorporate a new / more abstract concept of session? Not sure. But I picked Jetty because the code base "smells good" to me. It looks to be well thought out and extensible in the right places. And reliable so far! Grateful to have it. -Robert |
:) For our part, we didn't mean to come off as exaspirated. But as the "standards bearers" of legacy J2EE, I kind of think sessions are in the too broken to fix camp. I don't think they can be dragged to one interpretation or another without breaking a huge number of applications, as too many have used querks of various contains or a priori knowledge of the specific session stores to make workable applications, but that are just not portable. It is probably time for a new abstraction and to just deprecate sessions... maybe servlet 7.0? The intention of jetty is to be both a standards implementation, but also to be a flexible code base that doesn't "smell too bad" to be used (and "abused") in specific use-cases that are not covered by the standard. If you have need, then it is indeed reasonable to extend session handling APIs. So long as you know it is not standard! cheers |
You might want to just use the Not sure what you're trying to do will ultimately work, but you know your application best. Just make sure you've read all the doco on HttpSessions: https://www.eclipse.org/jetty/documentation/jetty-10/programming-guide/index.html#pg-server-session |
Thanks Jan but I noticed that the eviction policy for
Yep I'd be willing to contribute this code. :) It's not really a change of the existing |
Any of the eviction settings are effectively meaningless for the Note that you can still have long-lived sessions that aren't necessarily in the cache. They live inside the
Actually we would need an update of the existing |
If you look at this line of code, you can see that, if the session to remove is not found in cache, the session destroyed events will not get called. This line of code shows you that This line of code shows how |
It is a little more complicated than you think ;). If you look at the code for
Yup, in the case of the
I think you're mixing concepts here. If you don't want to cache sessions, then the idle timeout is unnecessary - the session cannot live past the end of the request. Note that it will still continue to exist in persistent store, there just isn't an in-memory representation of it. In this case, the |
Thank you @janbartel ! My last question for now: Is there a way to dynamically change the SessionCache strategy? @joakime Please feel free to cleanup this issue if you want. Certainly got into the weeds. |
@rfox12 not sure what you mean by the strategy? If you mean the eviction setting, then no. There can be multiple threads in the cache at one time so you would get indeterminate results. I should probably add some specific code to reject calling the setters after start. On any given Session you can change the max idle time in a thread-safe way. |
In light of some past discussions ...
We should think about how HttpSession behaves while in a WebSocket lifecycle.
Currently ...
The text was updated successfully, but these errors were encountered: