0

We have a Java web backend service running on 2 production servers with 2 JVMs in each of them, behind a load balancer in Websphere Application Server.

My Use Case:

  • Call an external API first time after deployment.
  • If Response.OK
    • Cache the response in an external datastore (not relevant for this question)
  • For the next client requests of the day and if the time of the requests are not equal to or immediately after a set of times (9:00, 11:00, 13:00, 15:00)
    • Return the cached response
  • If the client request happens to be on any given time in the set (9:00, 11:00, 13:00, 15:00)
    • Call the external API and update cache (not relevant again). Example., request comes at 9:00
  • For all the subsequent requests from 9:00 to 10:59 (because next time in the set is 11:00)
    • Return the cached response
  • At 11:00
    • Call the external API and update cache
  • And so on..

This way there are only four requests to the external API in a day as opposed to directly calling the external API for every request.

How can I achieve this at the application level in Java across all the production servers, accounting for the daylight saving time in a particular timezone, without any network or IO programming?

Note: The application does not use Spring boot. I'm trying to do this purely in Java.

Barani
  • 83
  • 1
  • 8
  • did you check https://stackoverflow.com/questions/11840059/how-to-run-a-java-program-under-cron-and-import-the-jars – sanjeevRm May 15 '21 at 07:32
  • Does this answer your question? [How to run a Java program under cron and import the jars](https://stackoverflow.com/questions/11840059/how-to-run-a-java-program-under-cron-and-import-the-jars) – sanjeevRm May 15 '21 at 07:33
  • @sanjeevRm I'll take a look at running cron jobs Sanjeev, but there must be some way to do this without any dependencies on external libraries, and just on Java, like using Scheduled Executor Service or type 4 UUID. – Barani May 15 '21 at 07:41
  • you can schedule task in java using `java.util.Timer` and `java.util.TimerTask` , Timer has `schedule` method, this involve Thread, can become complicated if not handled properly – sanjeevRm May 15 '21 at 07:53
  • Are you limited to 4 calls per jvm or 4 calls per all JVMs? If it is 4 per JVM simplest would be to pass your times (9,11..) as params, and simply store the time of last call in the cache, and refresh cache if it is older (sync refreshing block). If it is only 4 calls across your all JVMs, you would need to use shared cache and more complex refresh logic to allow only single concurrent refresh. – Gas May 17 '21 at 07:07
  • @Gas.. It is not a limitation, but more of an attempt towards cost saving. It would indeed be nice if there are only 4 calls across all JVMs and servers. But 8 outbound calls (4 requests x 2 servers, with application in one JVM each) would also be not so bad. When you mention shared cache do you mean caching on the server? If yes, that's not what I'm going for. But how can we achieve concurrent refresh or even refresh per server? – Barani May 18 '21 at 08:14
  • @Barani maybe I'm missing something... but you just proxy calls to external API via your service. That service caches the response, and checks if the result is not stale, if it is it makes call to external API. The level of synchronization depends on whether you want to have in server cache or shared (e.g.via db, or redis or something similar). If in server, then locking maybe done inside jvm (synchronized block), otherwise via db locks. While single thread is doing refresh, rest serves still cached response. – Gas May 18 '21 at 12:37
  • @Gas.. This makes perfect sense. Maintaining a lock value on an external database and decide when to update the lock in the application. If the request happens to be at 9 or few mins after, set the lock value to false with the request time appended, so that this would indicate that it is time for calling the API and update the cache, then at the end set the lock value to true, all in a synchronous execution. I hope I'm thinking along the same lines as you. But what happens when there are two simultaneous requests at 9:00? How to ensure concurrency here? – Barani May 20 '21 at 15:21
  • @Gas.. And what happens when it is the first request after the application deployment? We will have to call the external API at least once for the first time. Let's say we set another value in the database for first request and set it to true. But this would mean maintaining the database independent of the application.. i.e we have to make sure we set the first request value to true everytime the application is deployed and then set it to false later in the application. Is there a better way to tackle this? – Barani May 20 '21 at 15:24
  • @Barani When you make a call to DB you do `Select for update` in that case only one thread will be able to get the lock, make a call, update cache, release lock. The other concurrent threads will be waiting to get record lock. Yes, during first startup, if you start many apps at the same time, the other may wait till the first gets the value, but later if one thread will notice that cache is just being updated it will just return stale data for the last time, or wait till update is finished, depending on your requiremntes. – Gas May 20 '21 at 23:15

1 Answers1

1

Because you're using a JEE application server, if possible you should use a means that is spec compliant to provide the maximum portability. You didn't mention in your post whether you're using Liberty or traditional WebSphere.

If you're using Liberty, one JEE spec compliant way to manage asynchronous tasks is the ManagedScheduledExecutorService. If offers scheduling capabilities and handles the threading for you. Start with this info: https://www.ibm.com/docs/en/was-liberty/base?topic=manually-configuring-managed-scheduled-executors

If you're using traditional, the level of JEE support provided doesn't have a spec compliant means of handling asynch tasks in a JEE managed environment. You could use the JSE spec compliant ScheduledExecutorService, but unlike the Managed version, it's not designed for use in an app server env where you expect the server to manage all resources (like threads) for you. You would be responsible for threading and would need to consider the implications of using unmanaged threads in a JEE env (not a recommended pattern). To avoid this, you could use the WebSphere Scheduler service described here: https://www.ibm.com/docs/en/was/9.0.5?topic=calendars-scheduler

F Rowe
  • 2,042
  • 1
  • 11
  • 12