Refresh() method not working?

Thread is closed for posting
14 posts, 2 answers
  1. Gianni Araco
    Gianni Araco avatar
    18 posts
    Member since:
    Jul 2012

    Posted 17 Sep 2011 Link to this post

    Greetings!
    Once again I need the help of the community to solve another little trouble.
    After having dealt with multithreading and solved all the open point thanks to your help, now I'm facing another trial.
    My windows service is working, all its thread running and updating data accordingly.

    Now it's the turn of a web service that needs to fetch the updated data from the database.
    As the model is exactly the same, I've shared the project between the windows service and the web service, so they are referring to the same context dlls.

    What happens now? Everytime I call the web service, I obtain the value it loaded initially, no matter it has been updated in the meantime.
    So I tried to call this method:
    context.Refresh(Telerik.OpenAccess.RefreshMode.OverwriteChangesFromStore, context.Class1);

    without much success... the property I'm trying to fetch 0 was in the beginning and 0 remains as long as I don't restart the web service, though value is updated every second.
    When I restart the service I get, let's say, value 10 and it remains 10 for every call.
    Any suggestion?

    Thanks.
    Gianni Araco
  2. IT-Als
    IT-Als avatar
    381 posts
    Member since:
    Sep 2008

    Posted 19 Sep 2011 Link to this post

    Hi Gianni,

    Glad you got the Windows Service working.

    To my understanding you are sharing the Context assembly in your two solutions - one for the service and one for the web service. Thus the assembly is hosted in two processes. One for the Windows service and one for the app pool (if web service is hosted in IIS) backing your website.

    I don't remember if you have L2 caching turned on. Do you?

    And then I must understand your setup a bit further...  So the Windows Service updates an entity (every time it runs), right?  And you're trying to read a property of that updated entity in the web service, right?  and in the latter you do not see the changes (increased number) of the property right?

    Normally, if you're not using the L2 cache this should work like a charm. However, there might be issues if you have enabled the L2 cache.

    regards

    Henrik
  3. Gianni Araco
    Gianni Araco avatar
    18 posts
    Member since:
    Jul 2012

    Posted 19 Sep 2011 Link to this post

    Good morning Henrik, and thanks for your help.

    So yes, I have two solutions, one for the windows service and one for the web services.
    Both share a common project that is the OpenAccess model.
    L2 cache is enabled as the windows service has several threads that work on the same data so it's very useful to have them somewhat synchronized.

    The scenario is:
    1) The windows service runs indefinitely checking the data and updating some numbers depending on some rules.
    2) A client interface requests the data on demand via the web services and it should show the current state (updated numbers).

    I guessed that something about caching could have brought troubles on different solutions.
    But I would like to avoid to keep 2 different models updated as the database is exactly the same.
    Is there a way to enable/disable caching via code? Or it's something embedded in the generated classes?
    And anyway, why isn't the Refresh() method working? Maybe I misunderstood the way it works?

    Thanks.
    Gianni
  4. Answer
    IT-Als
    IT-Als avatar
    381 posts
    Member since:
    Sep 2008

    Posted 19 Sep 2011 Link to this post

    Ok, now the scene is set,let's focus on your web service.

    The L2 cache is bound to a Database (OA API object) instance in the Context... so you have only one Database instance per process, but you can spin off many context instances... and they are all bound to the same Database instance. That's exactly what happens when you use the "one thread - one context" approach discussed earlier.

    So you have 2 processes as discussed previous one for your service and one for the web service. Each having a Database instance and thus each having their own L2 cache.

    I am wondering if you really need the L2 cache in your web service, since you always want the latest value (written in the Windows Service) right?
    So in your web.config of the site that hosts your web service you turn off L2 cache.. Doing so you have one project (Windows service) with L2 cache enabled and one project (web service) with L2 cache disabled.

    The problem you're seeing is that the when first loaded in the web service the L2 cache does not get evicted again.. because the Database instance is kept alive with the app pool hosting your web site... however... if you restart your website/app pool you suddenly see your changes from the Windows Service, right?

    No evict takes place because you do not perform any changes to the persistent entity from your web service... so once read it stays in the L2 cache forever...
    Instead of disabling the L2 cache in the webservice project, you can perform an Evict on the entity type you wnat to read... I think it is placed in Context.Database.Cache.Evict(.......)  (there are several overloads)
    This will in effect evict the L2 cache of the specified entity type and re-read it from the database, thus you should see the real value. Something like this in your web service method...

    {
      // evict the all instances of the MyEntity type in L2 cache
      Context.Database.Cache.Evict(MyEntity);
      // Go on and get the entity - thus it is placed in L2 cache again
      MyEntity obj = ......
      ...
    }

    Hope this clears things up... as well as telling something about the workings of the L2 cache

    Regards

    Henrik
  5. Gianni Araco
    Gianni Araco avatar
    18 posts
    Member since:
    Jul 2012

    Posted 19 Sep 2011 Link to this post

    Perfect, I got the big picture.

    I'd say that at this point the best solution will be disabling the L2 cache in the web services as each call request only the latest data, and it's not going to modify anything; eventually it's going to add new records (I'm going to test if new records are evicted by the windows service).

    The mystery about Refresh() remains, but as I'm going to follow a different road it seems I'm not going to use it.
    Though I'd like to know why I don't get the expected result.

    Thanks again for the useful informations.
    Gianni
  6. IT-Als
    IT-Als avatar
    381 posts
    Member since:
    Sep 2008

    Posted 19 Sep 2011 Link to this post

    Hi Gianni,

    Perfect. Glad to help.

    Regarding the Refresh()...  I really think it should do the trick since it reloads the entity from the database store...as far as I know.

    Regards

    Henrik
  7. Zoran
    Admin
    Zoran avatar
    534 posts

    Posted 21 Sep 2011 Link to this post

    Hi Gianni, 

    Regarding the mystery with the Refresh() method: I believe that the object is always fetched from the Second  level cache and that is why you always see the same values in your objects. The reason for this behavior is that the that the object is obviously not evicted from the cache when it gets updated. The SecondLevel cache is synchronized by default when two or more threads operate on some OpenAccess persistent objects in the same process. However I believe that in your case you have two services, and I believe that means you have two different processes that read/write on the same data. In order to use the Second Level Caching capabilities of OpenAccess in a cross-process scenario, you need to configure the Second Level Cache further for such environment.

    Here is a help article that describes the cache cluster. This functionality was in fact developed to enhance web farms and other cluster scenarios. I believe your case does not really require this setup, but I believe this could provide to be valuable information for some future project. The help article I referred you to, is a bit out-dated, or at least it addresses the IObjectScope way of configuring OpenAccess. However you can do the setup by setting the required properties in the BackendConfiguration object that is passed in the OpenAccessContext constructor.

    Best wishes,
    Zoran
    the Telerik team

    Thank you for being the most amazing .NET community! Your unfailing support is what helps us charge forward! We'd appreciate your vote for Telerik in this year's SQL Server Community Awards. We are competing in TWO categories and every vote counts! VOTE for Telerik NOW >>

  8. Gianni Araco
    Gianni Araco avatar
    18 posts
    Member since:
    Jul 2012

    Posted 24 Sep 2011 Link to this post

    Greetings Zoran.
    Being able to sync different processes to leverage the L2 cache would be awesome! And that would fit my scenario as in the future scalability could be obtained with a web services farm.
    Too bad it seems that configuring it is far from being easy...
    I have added this code to the static GetBackendConfiguration() method of the context object:
    backend.SecondLevelCache.Synchronization.Enabled = true;
    backend.SecondLevelCache.Synchronization.AdministrationQueue = "AdmimQueue";
    backend.SecondLevelCache.Synchronization.Localpath = "Queue";
    backend.SecondLevelCache.Synchronization.MulticastAddress = "224.1.1.1:666";

    but when I call the web service or run the windows service I get this error:
    Length cannot be less than zero.
    Parameter name: length
     
       at Telerik.OpenAccess.SPI.Backends.ThrowException(Exception e)
       at Telerik.OpenAccess.RT.ExceptionWrapper.Throw()
       at Telerik.OpenAccess.RT.MSMQClusterImpl.Initialize()
       at Telerik.OpenAccess.RT.MSMQClusterImpl..ctor(OpenAccessClusterMsgHandler h, Boolean dbg, String multi, String loc, Int32 ap, String humanName, Guid sysName, Boolean pc, AsynchronousInputHandler ah, Int32 expirMS, String adminP)
       at Telerik.OpenAccess.RT.MSMQClusterTransport.Telerik.OpenAccess.Cluster.OpenAccessClusterTransport.Init(OpenAccessClusterMsgHandler msgHandler, String _serverName, String ident)
       at OpenAccessRuntime.DataObjects.PersistenceManagerFactoryBase.createStorageCache()
       at OpenAccessRuntime.DataObjects.PersistenceManagerFactoryBase.init()
       at OpenAccessRuntime.DataObjects.PersistenceManagerFactoryImp.init()
       at OpenAccessRuntime.DataObjects.PersistenceManagerFactoryImp..ctor(PropertySet properties, Object classloader)
       at OpenAccessRuntime.DataObjects.PersistenceManagerFactoryImp.getPersistenceManagerFactory(PropertySet props)
       at OpenAccessRuntime.DataObjects.BootstrapPMF.getPersistenceManagerFactory(PropertySet props)
       at Telerik.OpenAccess.RT.Helper.getPersistenceManagerFactory(PropertySet props)
       at Telerik.OpenAccess.RT.DatabaseAdapter.AssertPersistenceManagerFactory(String usr, String password, Boolean open)
       at Telerik.OpenAccess.RT.DatabaseAdapter.GetObjectScope(TransactionProvider provider)
       at Telerik.OpenAccess.Database.GetObjectScope(TransactionProvider provider)
       at Telerik.OpenAccess.OpenAccessContextBase.GetScope()
       at Telerik.OpenAccess.OpenAccessContext.GetAll[T]()
       at DeepRift9.ObjectModel.DR9Model.get_MyDatas() in L:\Develop\TestOA\TestOA.ObjectModel\TestOA.cs:line 327

    The method that returns this error is:
    public IQueryable<MyDatas> MyDatas
    {
        get
        {
            return this.GetAll<MyDatas>();
        }
    }

    and it seems that's because the collection is empty. But the error itself says me nothing about the relationship with the L2 cache synchronization. I can guess it's unable to load the data, but I have no clue why.
    Needless to say, without the synchronization part, it works (though it still does not updates the value).

    I was unsure about the address, so I tried setting it with a local IP (192.168.1.30:666) but I get another error saying that one of the parameters is invalid, so I'd say that 224.1.1.1:666 should work.

    Addendum:
    I tried another way, again without success. In the model partial class, I created a second static method GetBackendConfigurationNoCache() with the property backend.SecondLevelCache.Enabled = false and created the web service context in this way:
    using (MyModel context = new MyModel(MyModel.GetBackendConfigurationNoCache()))
    {
    ...
    }
    I hoped that this way the L2 cache would be disabled so that I could read data directly from the database, but it didn't work.
    Neither did the Refresh() method.

    If I am able to complete this scenario I will prove that this is the right tool to use.

    Any advice?
    Thanks.
    Gianni
  9. Answer
    Zoran
    Admin
    Zoran avatar
    534 posts

    Posted 26 Sep 2011 Link to this post

    Hi Gianni Araco,

     This really looks that like a problem with the MSMQ installation on the machine that you test against. I am sending you a simple tool which we use here internally to check about the MSMQ functionality on an OS level.

    Please try to connect to 224.1.1.1:666 using this tool and give us feedback for the results. Also I have to tell you beforehand that this tool works with the latest version of OpenAccess, which means that you should install the latest service pack we release as well. There are other fixes in the MSMQ layer of the product in this release so I strongly advise you to continue your tests against this version. 

    As for the Addendum: The metadata that OpenAccess uses internally is being cached ones it is initialized and the key to the cache is the connection string Id. So you do not see a change in the caching behavior because you have already instantiated a context with the Second Level Cache enabled before using the other BackendConfiguration object. What you can do in this case, is to have the same connection string i your app.config file, but with a different connection id. Passing the new connection id together with the new BackendConfiguration object to the constructor of your context instances will switch the level 2 cache off for those contexts that use the new connection id. The 2nd level cache will still be switched on for the other context instances that are initialized with the default context constructor. 

    Kind regards,
    Zoran
    the Telerik team

    Thank you for being the most amazing .NET community! Your unfailing support is what helps us charge forward! We'd appreciate your vote for Telerik in this year's SQL Server Community Awards. We are competing in TWO categories and every vote counts! VOTE for Telerik NOW >>

  10. Patrice Boissonneault
    Patrice Boissonneault avatar
    35 posts
    Member since:
    Nov 2009

    Posted 29 Sep 2011 Link to this post

    When is Telerik going to offer another L2 Cache Sync mechanism?  Working with MSMQ is so painful.  I've been trying to set things up properly in our farm for weeks, yet we still see evict calls that randomly do not get to all the servers in the farm.

    PLEASE, give us another L2 Cache Sync mechanism or at least expose the L2 Cache API so that we can build our own.

    At the very least, a diagnostic tool that we could run on the servers to make sure MSMQ is properly installed to work with Telerik would be very helpful.

    Thanks.
  11. Patrice Boissonneault
    Patrice Boissonneault avatar
    35 posts
    Member since:
    Nov 2009

    Posted 29 Sep 2011 Link to this post

    Zoran, could you also send me the tool for diagnosing MSMQ issues please?

    Thanks.
  12. Gianni Araco
    Gianni Araco avatar
    18 posts
    Member since:
    Jul 2012

    Posted 01 Oct 2011 Link to this post

    Greetings Zoran,
    sorry for the delay in answering.

    With a bit of effort, I managed to create a second connection without cache and it seems to work!
    Though I've had to create a method that retrieves the metadata source. I haven't found it exposed anywhere.
    And I have to say that the documentation can be very "minimal" at times.

    For the MSMQ part, I didn't reiceived your tool, maybe it has been tagged as spam and I didn't noticed it.
    Could you please sent it again?

    Thanks again for the great support.
    Gianni Araco
  13. Zoran
    Admin
    Zoran avatar
    534 posts

    Posted 03 Oct 2011 Link to this post

    Hi Gianni Araco,

     Please let me apologize, it was a glitch on my side for trying to send you the tool in a forum thread. Attaching such files is not possible in a public forum post, so I will ask you to open a support ticket on the mater which will allow me to attach the tool for you.

    @Patrice: I will send you the tool in your respective support thread.

    Greetings,
    Zoran
    the Telerik team

    Thank you for being the most amazing .NET community! Your unfailing support is what helps us charge forward! We'd appreciate your vote for Telerik in this year's SQL Server Community Awards. We are competing in TWO categories and every vote counts! VOTE for Telerik NOW >>

  14. Zoran
    Admin
    Zoran avatar
    534 posts

    Posted 03 Oct 2011 Link to this post

    Hello Patrice Boissonneault,

     I just checked and saw that my colleague Ralph has already sent you the sample tool for checking the MSMQ settings on a machine. Just mentioning that the tool he has sent you is the same one that I have mentioned in this thread. If you have some feature request after giving it a try, we will be glad to respond.

    Regards,
    Zoran
    the Telerik team

    Thank you for being the most amazing .NET community! Your unfailing support is what helps us charge forward! We'd appreciate your vote for Telerik in this year's SQL Server Community Awards. We are competing in TWO categories and every vote counts! VOTE for Telerik NOW >>

Back to Top