Grails woes again - sessions and stale objects

classic Classic list List threaded Threaded
9 messages Options
Reply | Threaded
Open this post in threaded view
|

Grails woes again - sessions and stale objects

grampajohn
Administrator
Now that we are trying to run the server, and running tests that exercise the system over multiple clock cycles, we are encountering a very nasty problem with stale objects. This is caused, I believe, by keeping context around in various objects past the end of sessions. Since we are not driving the system with http requests, which is what Grails is designed for, it's a little hard to tell when sessions start and end. But it seems clear that there's a new session with each clock tick.

Grails services are really supposed to get requests from controllers, which in turn collect data from a user's browser. That data is used by a service to pull other data from the database, process it in some way, perhaps store stuff in the database, and return results to the user. The service is not supposed to keep anything around from session to session - it becomes "stale" and you get "data integrity" errors if you try to use it.

Unfortunately many of our services, such as accounting and tariff market, keep a fair amount of state around, and it's a little hard to know which data is intra-session and which is across sessions. I'm not quite sure of the right way to handle this problem; right now I'm thinking that using Grails to build our server was a huge mistake.

If anyone knows how this is really supposed to work, please let me know.

Thanks -

John
Reply | Threaded
Open this post in threaded view
|

Re: Grails woes again - sessions and stale objects

adis
CONTENTS DELETED
The author has deleted this message.
Reply | Threaded
Open this post in threaded view
|

Re: Grails woes again - sessions and stale objects

ddauer
So why don't we save state in the database?

On Tue, Apr 26, 2011 at 2:25 PM, adis [via Power TAC Developers] <[hidden email]> wrote:
I might be misunderstanding the issue here, but will clearing the session data help?

Something like calling this object method from the controller:

session = sessionFactory.getCurrentSession()
session.clear()
Reply | Threaded
Open this post in threaded view
|

Re: Grails woes again - sessions and stale objects

grampajohn
Administrator
On 04/26/2011 07:31 AM, ddauer [via Power TAC Developers] wrote:
> So why don't we save state in the database?

There's a fair amount of transient state that's not currently in the
database, and that would break good modularity if we added it in the
"obvious" ways. For example, the tariff market needs to keep track of
the tariffs that have arrived but have not yet been published. The
"pending" state of these tariffs is not an intrinsic property of a
tariff, in my opinion, although it could be added. Simpler, perhaps, to
switch from a list of tariffs to a list of tariff IDs in the tariff
market, and then re-fetch the tariffs when it's time to publish.

I think a big part of the problem is that I am still learning how to
make Grails do things it was not intended to do, and I have a lot of
experience building simulators. I keep running into situations where
things do not work in Grails the way I expect them to.

John

Reply | Threaded
Open this post in threaded view
|

Re: Grails woes again - sessions and stale objects

grampajohn
Administrator
In reply to this post by grampajohn

I think I finally understand more clearly what we are doing wrong. Grails is a convention-driven web-app framework, and we are not following its conventions correctly. Here are the rules as I understand them:

  • Domain types live in the database. You can retrieve them by ID or by some query, and if necessary you can update and store them back. This cycle needs to be completed within a "session" - and once the session is over, the object is "stale" and will not match the same object freshly retrieved from the database. Any attempt to save some other object that contains a reference to this stale object will produce a data integrity violation.
  • Service types are typically singletons, but that's only one option - it's explained in Section 8.2 of the Grails docs. If services are completely stateless, then non-singleton models can work, but we are building a simulator, and so it makes sense for many services to have some state. However, that state cannot contain domain instances, because they will become stale. It can contain domain instance IDs.
  • Sessions in Grails are normally scoped to an http request, but our simulator is not driven primarily by http requests. It is driven by the clock. It's not exactly clear from the documentation, but I'm guessing that one of the things the Quartz Scheduler is doing for us is creating a new session for each clock tick. That means that you cannot keep references to domain objects around from one clock tick to another - you need to re-retrieve them on each tick.
We have been violating this model in two significant ways that I am aware of.

First, we have services that keep domain objects around. I solved that problem in TariffMarketService by getting rid of the list of un-published tariffs, adding a PENDING state to tariffs, and then retrieving all the PENDING tariffs when it's time to publish, changing their states to OFFERED, and saving them again. In AccountingService we keep around a list of pending transactions that have not yet been forwarded to brokers. Because those can become stale, I just re-retrieved them using the IDs from the (potentially) stale ones before sending them.

Second, we have domain objects (Abstract Customer is the most obvious one, but DefaultBroker will also be one soon) that are trying to be services, by implementing clock-driven behaviors. This cannot work, because the clock is then making method calls on stale objects, which cannot even save themselves. Instead, all clock-driven behaviors need to be factored out into services which, when activated, retrieve their domain instances from the database, and when finished, save those instances back.

In short, services cannot inherit from domain types, and they cannot keep references to domain objects across session boundaries. Domain types cannot be services. I believe that once we clear up this confusion in our minds and in our code base, many of our problems will go away. Well, a few of them at least...

Does this make sense? Have I got it right? Does anyone have deeper insight on this issue?

John

Reply | Threaded
Open this post in threaded view
|

Re: Grails woes again - sessions and stale objects

grampajohn
Administrator
OK, I think I have a solution to the problem of non-relational data (lists of non-domain types, arrays, etc.) in Domain types. There are two possibilities: (1) make them relational, and (2) offload non-relational data.

In some cases (1) is the right solution, but there are cases where we have large multi-dimensional arrays of numbers, and it makes no sense to try to cram those into the database, as long as the data is reproducible. Examples where this seems like a poor solution are Tariff and Village.

Using approach (2) I have refactored the non-relational tier list and rate map out of Tariff into TariffRateService in powertac-common. Tests pass. I will do a full server test after I take care of some urgent University business.

Please let me know if you see any problems with this.

Cheers -

John
Reply | Threaded
Open this post in threaded view
|

Re: Grails woes again - sessions and stale objects

grampajohn
Administrator
Here's the next problem with Grails: if you have a Domain object with an association and try to serialize it (with XStream), Grails does not fetch the associations, so you get nulls in all the non-primitive fields. If you turn off lazy loading, you don't get the actual objects back; you get hibernate proxies. For example, in TariffSpecification.broker, you get not a Broker but a org.powertac.common.Broker_$$_javassist_64. XStream just barfs on that. Right now, that means we cannot publish tariffs. Any suggestions would be welcome.

John
Reply | Threaded
Open this post in threaded view
|

Re: Grails woes again - sessions and stale objects

grampajohn
Administrator
grampajohn wrote
Here's the next problem with Grails: if you have a Domain object with an association and try to serialize it (with XStream), Grails does not fetch the associations, so you get nulls in all the non-primitive fields. If you turn off lazy loading, you don't get the actual objects back; you get hibernate proxies. For example, in TariffSpecification.broker, you get not a Broker but a org.powertac.common.Broker_$$_javassist_64. XStream just barfs on that. Right now, that means we cannot publish tariffs. Any suggestions would be welcome.
OK, that weird classname is what's known as a CGLIB proxy - it's used by hibernate to intercept calls that traverse database tables. So when you store a TariffSpecification in the database and then restore it, the thing in the broker field is not a Broker but one of these proxy things. I have spent many hours looking for a way to resolve this, and I'm out of time today. Our released system will not be able to serialize such objects until we have a solution to this.

Would someone please remind me why Grails was a good idea? I'm not a happy camper right now.

John
Reply | Threaded
Open this post in threaded view
|

Re: Grails woes again - sessions and stale objects

adis
CONTENTS DELETED
The author has deleted this message.