Skip to content
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

SessionAttributes defined in the controller are not populated from the HttpSession object when the web session fails over to a new server in the cluster [SPR-9047] #13686

Closed
spring-projects-issues opened this issue Jan 23, 2012 · 7 comments
Assignees
Labels
in: web type: enhancement
Milestone

Comments

@spring-projects-issues
Copy link
Collaborator

spring-projects-issues commented Jan 23, 2012

Erik Love opened SPR-9047 and commented

We have been working towards implementing a web site using Spring 3.0.5. However, when working in a clustered environment, we have found that variables defined as part of the @SessionAttribute annotation are not populated from the HttpSession when the server instance fails over to a different server in the cluster.

It looks like the org.springframework.web.bind.annotation.support.HandlerMethodInvoker calls the getActualSessionAttributeNames() method of the HandlerMethodResolver in order to get a list of all session attributes/variables that should be placed into the Model. The issue, however, is that the Set used to store the names (actualSessionAttributeNames) is not populated during the init of HandlerMethodResolver. It is only populated as the HandlerMethodResolver.isSessionAttribute method is called which doesn't happen until AFTER the call to the getActualSessionAttributeNames() is made by the HandlerMethodInvoker. This is resulting in the SessionAttribute values being re-initialized and the loss of all conversational data for the Controller.

We have temporarily gotten around this issue by modifying the HandlerMethodResolver code to have it add all session attribute names to the actualSessionAttributeNames during the init (around line 107 in the HandlerMethodResolver code). We have not found any other solution and most forums/posts/blogs/examples suggest using the WebRequest or HttpSession objects directly.


Affects: 3.0.5

Attachments:

@spring-projects-issues
Copy link
Collaborator Author

spring-projects-issues commented Jan 24, 2012

Rossen Stoyanchev commented

@SessionAttributes lists the names of model attributes to store in the session. Once attributes matching the description appear in the model, they get stored in the session and are kept there untill SessionStatus.setComplete() is called. Thus the "actual list" of session attributes is built up gradually as matching attributes appear in the model. Keep in mind that @SessionAttributes can be configured in two ways -- with attribute names and with attribute types. For the latter what the actual attributes are cannot be known up front.

That said I can understand the issue you're describing in a clustered environment where when you switch over the knowledge of actual session attribute names is lost. Keep in mind though that when an @ModelAttribute argument is resolved, we try to look up the object in the session anyway, i.e. regardless whether it's in the list of actual session attributes or not (in 3.0.x code that's HandlerMethodInvoker line 763). So I wonder how the problem actually manifests itself for you? Maybe provide an example of your controller code and where/how it fails after the failover (I presume it works fine otherwise).

@spring-projects-issues
Copy link
Collaborator Author

spring-projects-issues commented Jan 24, 2012

Erik Love commented

Thanks for getting back to me!

I must be missing something then, because the sample controller (see attached) is very incredibly simplistic and the @ModelAttribute is defined for the one and only public method...and it gets wiped out on a cluster failover.

What I am seeing in the code is this:

  1. HandlerMethodInvoker.invokeHandlerMethod (line 139) is called
  2. at line 145, the method calls HandlerMethodResolver.getActualSessionAttributeNames which does not return any names since the isSessionAttribute method was never called to add the session names to the Set.
  3. the for loop at 145 does not, therefore, add anything to the implicit model
  4. The code then loops through all of the attribute names (151-170) and if not found in the implicit model, calls the method to initialize the variable...adding that value to the implicit model. (defaults the String in my controller to be an empty string)
  5. At line 179, the call to resolveHandlerArguments is made
  6. At line 363, the call to resolveModelAttribute is made
  7. resolveModelAttribute is the only other method (other than the updateModelAttribute which shouldn't come into play yet) that access the sessionAttributeStore (line 767). However, it doesn't appear to do so in this case since at line 761 it checks the implicit model for the variable and finds the key due to bullet SPR-7752 - EntityManager proxy now exposes provider specific interface. #4 above.

I did notice that types would not be set in the HandlerMethodResolver change I made. However, since my change was concerned with named items in the @SessionAttributes annotation, it worked fine... Just to make sure that I am clear...this is only an issue when using SessionAttributes. ModelAttributes which are returned to the controller as part of the request are still populated with the correct values. It is only those attributes which are stored in session and attempted to be used during the request that are lost.

In my controller, I am simply appending the server's ip address and port to each request, expecting to see the full history when the session fails over, including the new server ip and/or port. However, until I made the change, the value after failover was as if I came to the controller for the first time (the value from line 34).

I would rather not modify our spring deployment, but I also do not want to modify all of our controllers to use some alternate approach as recommended by the various blogs that have also expressed issues with the SessionAttributes functionality. Hopefully I am just missing something stupid/simple.

Any help would be great!

@spring-projects-issues
Copy link
Collaborator Author

spring-projects-issues commented Jan 24, 2012

Erik Love commented

Super simple Controller used when debugging the issue (vs. modifying our more complex forms).

@spring-projects-issues
Copy link
Collaborator Author

spring-projects-issues commented Jan 24, 2012

Erik Love commented

lol sorry! Thought that the previous comment would be associated with the file that I attached!

@spring-projects-issues
Copy link
Collaborator Author

spring-projects-issues commented Jan 24, 2012

Rossen Stoyanchev commented

I see. After the failover the @ModelAttribute method is used because the attribute "myTest" is not in the model. If it was in the model because it was recognized as a session attribute and found in the session, then the return value of the @ModelAttribute method would have been ignored.

We can consider populating the "actual list" of session attributes at initialization with whatever is known (i.e. session attributes specified by name). It would however lead to a subtle change of behavior. The controller will now more aggressively fetch attributes from the session and also remove attributes from the session when SessionStatus.setComplete() is called, potentially removing attributes it didn't create. Then again since we're only doing this for attributes explicitly named in @SessionAttributes, I think it's relatively safe to do so.

@spring-projects-issues
Copy link
Collaborator Author

spring-projects-issues commented Feb 3, 2012

Rossen Stoyanchev commented

Changing to "improvement" reflecting the fact this is a functional limitation that doesn't work with clustered session failover yet.

@spring-projects-issues
Copy link
Collaborator Author

spring-projects-issues commented Feb 3, 2012

Rossen Stoyanchev commented

The change has been made and will be available in 3.1.1. However note it only applies to the new @MVC support classes in 3.1 (RequestMappingHandlerAdapter, etc). While we still have the 2.5-3.0 @MVC support classes, we generally no longer add functional improvements or new features to them. Hopefully the workaround you have is not too much inconvenience to the time you upgrade to 3.1.1.

@spring-projects-issues spring-projects-issues added type: enhancement in: web labels Jan 11, 2019
@spring-projects-issues spring-projects-issues added this to the 3.1.1 milestone Jan 11, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: web type: enhancement
Projects
None yet
Development

No branches or pull requests

2 participants