Rest API and Caching

Discussions relating to the REST API of Jiwa 7.

Re: Rest API and Caching

Postby Mike.Sheen » Sat Aug 25, 2018 6:30 pm

SBarnes wrote:Is there any way of solving this without a major version release?


Hi Stuart,

I don't know yet if a new build of the software will be required, or if we can do this by providing a plugin update.

Our builds use Major.Minor.Release versioning - e.g.:
7.0.175
7.1.0
7.2.0

We only change any of those numbers if a data structure change is made - so if we do need to do a data structure change for this, then it will be a new Release version number change - so 7.2.x, where x == the Release version.

Mike
Mike Sheen
Chief Software Engineer
Jiwa Financials

If I do answer your question to your satisfaction, please mark it as the post solving the topic so others with the same issue can readily identify the solution
User avatar
Mike.Sheen
Overflow Error
Overflow Error
 
Posts: 2444
Joined: Tue Feb 12, 2008 11:12 am
Location: Perth, Republic of Western Australia
Topics Solved: 756

Re: Rest API and Caching

Postby SBarnes » Sun Aug 26, 2018 11:50 am

Thanks Mike,

Let me know if you need anything tested given I have a Redis environment etc set up.
Regards
Stuart Barnes
SBarnes
Shihan
Shihan
 
Posts: 1618
Joined: Fri Aug 15, 2008 3:27 pm
Topics Solved: 175

Re: Rest API and Caching

Postby SBarnes » Sat Sep 28, 2019 3:18 pm

Is there any update on at ETA as to when caching could be introduced?
Regards
Stuart Barnes
SBarnes
Shihan
Shihan
 
Posts: 1618
Joined: Fri Aug 15, 2008 3:27 pm
Topics Solved: 175

Re: Rest API and Caching

Postby Mike.Sheen » Tue Oct 08, 2019 12:41 pm

SBarnes wrote:Hi Mike,

Is there any way of solving this without a major version release?


Hi Stuart,

Possibly - but to be honest it's currently not a priority for us as we've only had yourself asking for caching.

We did have one customer ask for a transparent cache / proxy solution but only because they wanted it for a specific purpose - they had one route in their API to allow customers to retrieve stock levels of products, so we provided a simple .NET Core 2.2 application to run on a small linux box which cached that one response for them as their upload speed from their on-premise Jiwa database was limited to 1Mb/s, and they also wanted to be able to provide a cached response in the event the link was down or the Jiwa database was offline.

I genericised it somewhat and it allows multiple routes to be cached to be defined in a config file, and also if to forward POST, DELETE, PATCH and PUTs to the Jiwa API - it might be enough for your needs - you can download the source from here.

Another alternative is a more comprehensive solution like Apache Traffic Server.

Mike
Mike Sheen
Chief Software Engineer
Jiwa Financials

If I do answer your question to your satisfaction, please mark it as the post solving the topic so others with the same issue can readily identify the solution
User avatar
Mike.Sheen
Overflow Error
Overflow Error
 
Posts: 2444
Joined: Tue Feb 12, 2008 11:12 am
Location: Perth, Republic of Western Australia
Topics Solved: 756

Re: Rest API and Caching

Postby SBarnes » Fri Oct 11, 2019 5:41 pm

The approach of the .net core project is interesting, I haven't had to use .net core yet although given Microsoft's stance and announcements with the release of .net core 3, it's obviously going to become the way forward, ah the joys of having to learn something new again.
Regards
Stuart Barnes
SBarnes
Shihan
Shihan
 
Posts: 1618
Joined: Fri Aug 15, 2008 3:27 pm
Topics Solved: 175

Re: Rest API and Caching

Postby Mike.Sheen » Fri Nov 01, 2019 6:10 pm

SBarnes wrote:The approach of the .net core project is interesting, I haven't had to use .net core yet although given Microsoft's stance and announcements with the release of .net core 3, it's obviously going to become the way forward, ah the joys of having to learn something new again.


It's definitely the future - .NET Framework 4.8 is the last .NET Framework, only .NET Core will see new versions - but after 3.1 they're rebranding it to .NET 5 because that's less confusing, apparently.

.NET Framework is dead! Long live .NET!
Mike Sheen
Chief Software Engineer
Jiwa Financials

If I do answer your question to your satisfaction, please mark it as the post solving the topic so others with the same issue can readily identify the solution
User avatar
Mike.Sheen
Overflow Error
Overflow Error
 
Posts: 2444
Joined: Tue Feb 12, 2008 11:12 am
Location: Perth, Republic of Western Australia
Topics Solved: 756

Re: Rest API and Caching

Postby SBarnes » Sat Nov 02, 2019 3:39 pm

Yeah, I remember them announcing they were going to run both technologies in in tandem and had thougth at the time that would double the effort so I am not surprised at the reversal.

I've got to admit for web development Razor pages which are in line with a more MVVM model than the MVC model and Blazor certainly look interesting, provided of course Blazor gets to commercial release and doesn't become Silver light v2.

Does this mean at some point in time in the near future Jiwa will port to core even though you don't run outside of windows client wise?
Regards
Stuart Barnes
SBarnes
Shihan
Shihan
 
Posts: 1618
Joined: Fri Aug 15, 2008 3:27 pm
Topics Solved: 175

Re: Rest API and Caching

Postby Mike.Sheen » Sat Nov 02, 2019 4:00 pm

SBarnes wrote:I've got to admit for web development Razor pages which are in line with a more MVVM model than the MVC model and Blazor certainly look interesting, provided of course Blazor gets to commercial release and doesn't become Silver light v2.


Server-side Blazor is commercial in .Net Core 3.0. The client side Blazor is still experimental, but it's moving along - the mono team need a few bits to complete before that becomes possible, which they've been putting out incrementally.

SBarnes wrote:Does this mean at some point in time in the near future Jiwa will port to core even though you don't run outside of windows client wise?


My current opinion is if we're going to build something in .NET Core it'll mean a lot of breaking changes, so if we're going to introduce that pain of change, we'd go the whole hog and rebuild from scratch. In other words, I don't see us porting our current code base to .NET Core.
Mike Sheen
Chief Software Engineer
Jiwa Financials

If I do answer your question to your satisfaction, please mark it as the post solving the topic so others with the same issue can readily identify the solution
User avatar
Mike.Sheen
Overflow Error
Overflow Error
 
Posts: 2444
Joined: Tue Feb 12, 2008 11:12 am
Location: Perth, Republic of Western Australia
Topics Solved: 756

Re: Rest API and Caching

Postby Mike.Sheen » Thu Nov 14, 2019 6:14 pm

I've been exploring a bit to see what this is going to take.

ServiceStack already gives us an in memory cache for free, but if you prefer Redis or something else then you can override that behaviour using a plugin with something like the following in the Configure method:

Code: Select all
container.Register<IRedisClientsManager>(c =>
    new RedisManagerPool("localhost:6379"));

container.Register(c => c.Resolve<IRedisClientsManager>().GetCacheClient());


Then - in order to make use of the cache, we've got 3 options for having responses cached:
  • ToOptimizedResultUsingCache technique - which looks pretty neat, but I can't get it to return anything than gibberish (seems to be returning a compressed response which isn't indicated as such)
  • Use the CacheResponse attribute around either services or the methods
  • Manually manage the cache

ToOptimizedResultUsingCache would be my preferred method, as it promises the lowest possible response time for a cached result, and is an elegant solution. We'd simply wrap our existing code in our GETs with something like this:

Code: Select all
[Authenticate]      
public JiwaFinancials.Jiwa.JiwaServiceModel.Debtors.Debtor Get(DebtorGETRequest request)
{
   string key = UrnId.Create<JiwaFinancials.Jiwa.JiwaServiceModel.Debtors.Debtor>(request.DebtorID);
   var expireInTimespan = new TimeSpan(1, 0, 0);
   return base.Request.ToOptimizedResultUsingCache(base.Cache, key, expireInTimespan, ()=>
   {
      // Existing code in the Get method for a debtor gets moved in here
   });
}


An expiry timespan doesn't need to be provided - it's optional, so not providing one would make it never expire - we'd have to manually invalidate cache entries if necessary.

The CacheResponse attribute approach is simple, but it's properties (such as expiry time) are set in-code at compile time - we'd probably want to set that from a setting or field in the database.

Code: Select all
[CacheResponse(Duration=60, MaxAge=30)]
public JiwaFinancials.Jiwa.JiwaServiceModel.Debtors.Debtor Get(DebtorGETRequest request)
{
   ...
}


Manually managing the cache is the most flexible option - and it's quite simple - for example caching the GET on /Debtors/{DebtorID} would be replacing the existing service method with this:

Code: Select all
[Authenticate]      
public JiwaFinancials.Jiwa.JiwaServiceModel.Debtors.Debtor Get(DebtorGETRequest request)
{
   string key = UrnId.Create<JiwaFinancials.Jiwa.JiwaServiceModel.Debtors.Debtor>(request.DebtorID);
   JiwaFinancials.Jiwa.JiwaServiceModel.Debtors.Debtor debtorDTO = base.Cache.Get<JiwaFinancials.Jiwa.JiwaServiceModel.Debtors.Debtor>(key);
   
   if (debtorDTO != null)
      return debtorDTO;
   
   JiwaApplication.Manager manager = this.SessionAs<JiwaAuthUserSession>().Manager;
   JiwaFinancials.Jiwa.JiwaDebtors.Debtor Debtor = Helper.Service.GetMaintenanceBusinessLogic<JiwaFinancials.Jiwa.JiwaDebtors.Debtor>(manager, this, request.DebtorID,
      (d, m, s) =>
      {
         d.Read(request.DebtorID);
         if (Helper.Service.IsStateful(s))
         {
            m.ObjectDictionary.Add(d.DebtorID, d);
         }
      });

   debtorDTO = Debtor.DTO_Serialise();
   base.Cache.Set<JiwaFinancials.Jiwa.JiwaServiceModel.Debtors.Debtor>(key, debtorDTO, DateTime.Now.ToUniversalTime.AddSeconds(60));         
   return debtorDTO;
}


Obviously, for this to be useful we'd have to also set the cache entry on POST and remove on DELETE, and generally invalidate the cache entry whenever the debtor changes. We could leverage our existing handlers that we use for webhooks (debtor saved) and put code in there to invalidate or refresh the cache entry - but I still worry about the cache getting stale and compromising the integrity of the system - and this does not just apply to the implementation of manual caching of responses, but all strategies.

I think a good approach is to add the logic in for caching and provide a way of setting a flag per route if that response is to be cached, and how long for. So this would be opt-in and this way it can always be turned off if problems occur.
We don't have anywhere to store that information, so a plugin could perhaps turn on caching once we add some fields to the standard REST API plugin - so something like this:

Code: Select all
public class RESTAPICachingPlugin : System.MarshalByRefObject, JiwaFinancials.Jiwa.JiwaApplication.IJiwaRESTAPIPlugin
{
   public void Configure(JiwaFinancials.Jiwa.JiwaApplication.Plugin.Plugin Plugin, ServiceStack.ServiceStackHost AppHost, Funq.Container Container, JiwaApplication.Manager JiwaApplicationManager)
   {
      // Add using the request type by adding to the static property CachedResponses which is a List<CacheResponseInfo> - CacheResponseInfo has an overloaded constructor each taking 2 arguments
      JiwaFinancials.Jiwa.JiwaServiceModel.RESTAPIPlugin.CachedResponses.Add(new CacheResponseInfo(typeof(DebtorGETRequest), new TimeSpan(1, 0, 0)));
      
      // Add using the route
      JiwaFinancials.Jiwa.JiwaServiceModel.RESTAPIPlugin.CachedResponses.Add(new CacheResponseInfo("/Debtors/{DebtorID}", new TimeSpan(1, 0, 0)));
   }
}


So, this is where I'm at so far with this. We should be able to get this done such that it's just plugin changes to our standard REST API plugin - so we should be able to make it all work for 07.02.01 or even 07.02.00

EDIT: So I've worked out why the ToOptimizedResultUsingCache was returning gibberish. The response was compressed TWICE. This was due to the service class being decorated with the [CompressResponse] attribute, and changing the method to return the result of ToOptimizedResultUsingCache meant that the response got compressed twice.

From the ServiceStack docs on compression:

Note using [CompressResponse] is unnecessary when returning cached responses as ServiceStack automatically caches and returns the most optimal Response - typically compressed bytes for clients that supports compression.


Which kinda sucks because now we can't have opt-in caching at runtime unless we remove the [CompressResponse] attribute from all our service classes, which would mean non-cached routes won't return a compressed response.
Mike Sheen
Chief Software Engineer
Jiwa Financials

If I do answer your question to your satisfaction, please mark it as the post solving the topic so others with the same issue can readily identify the solution
User avatar
Mike.Sheen
Overflow Error
Overflow Error
 
Posts: 2444
Joined: Tue Feb 12, 2008 11:12 am
Location: Perth, Republic of Western Australia
Topics Solved: 756

Re: Rest API and Caching

Postby SBarnes » Thu Nov 14, 2019 6:41 pm

Hi Mike,

Thanks for having a look at this, I think the idea of being able to enable caching or not would be a good idea, my only question here would be does it support custom / added in routes when the api is extended?

As for Redis, I can tell you if you are running it as a local service on a server it is fairly reliable but under Azure you can get some nasty timeouts with it when used for session management and it can be expensive to run.

It would also be nice but I don't think this is possible, to be able to control what routes require authentication or not, i.e. the option of opting a route out of authorisation if you wanted to, but I realise that might be a big ask.
Regards
Stuart Barnes
SBarnes
Shihan
Shihan
 
Posts: 1618
Joined: Fri Aug 15, 2008 3:27 pm
Topics Solved: 175

PreviousNext

Return to REST API

Who is online

Users browsing this forum: No registered users and 3 guests

cron