Alternate to scheduled a task which may be canceled in future - java

In our server, We have provided one feature to send request to another server on specific time.
The scenario is as follow:
Server1 is send request for Session1 to our server
Request contains a time on which we have to send request to Server1 with same session-ID
We have achieve this by scheduling request on specific time.
Ex.
Session1 request received from Server1 on 10:00 AM and time given is 11:00 PM, so we scheduled that request for 11:00 PM.
The only problem is session may be terminated before time and we have to cancel the scheduled task for that session.
The ratio of session expired before given time is 10:8 i.e 8 out of 10 will terminated before time.
Java ScheduleThreadPool will only mark tha task to cancel when cancel on task will be called but does not remove the task.
I can not call Queue.purge() method to remove canceled task because the number of canceled task may be in lac ex. 2 lac
other solution is,
I can manage Map of <Session-ID, Time>, and on hourly basis I will check tha number of session-ID which will need to authenticate in next hour and scheduled only that session-id.
It will reduce some overhead because I will remove session-ID from map if it will terminated before time.
please suggenst any other soution better than these or any changes in existing to optimize the above solution

If using a ScheduledThreadPoolExecutor is ok for you: There's an option in the API that lets you remove canceld tasks by default: http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ScheduledThreadPoolExecutor.html#setRemoveOnCancelPolicy(boolean)

Related

How Can I Trigger An Action 30 Days After A Date?

I have a requirement to update a field if a payment date is 30 days late.
Is it possible to trigger an action to occur 30 days after the payment date?
The process is likely to restart in-between those times so it can't be in-memory and it can't be a relative date.
I can create an endpoint like /api/paymentdates so that it could be called from something else like cron.
However, there are likely to be a over a million items at some point in the future, each with its own date.
Is there an effective way to trigger a task like this or is the only option to run a task every morning and query the database?
You can make use of a Queue Triggered Function (Storage Queue or Service Bus Queue). Basically what you will do is put a message in a queue and keep it invisible for 30 days (it is called initial visibility timeout in storage queue and scheduled message in service bus queue).
The message will only appear in the queue after its invisibility expires and the Function will be triggered at that time. Once the Function is triggered, you can do whatever processing you want to do on that message.
You may find following links useful:
https://learn.microsoft.com/en-us/azure/azure-functions/functions-bindings-storage-queue
https://learn.microsoft.com/en-us/azure/azure-functions/functions-bindings-service-bus

Send response after task from queue finishes to HttpSession (in GAE)

I'm implementing a basic Task Queue in the Google App Engine. Nothing fancy as I'm learning the introductions. The (push) queue works fine, but I'd like to send a little confirmation (or fail) message to the user of the relevant http session when the task is finished.
The way my structure is setup:
a HttpServlet receives an incoming HttpServletRequest
some info is retrieved from the HttpSession and is used to produce a task + store it in the task queue
another HttpServlet (the worker) receives an incoming request from the queue to execute the task
task gets executed
(this is the step I didn't manage to implement:) Send some info to a .jsp for the HttpSession that inserted the task in the queue
Normally I would do this by retrieving the session from the HttpServletRequest, but in this case, the one initiating the request is the queue itself (and not the user who initiated the task). I can't pass the HttpSession as an array of bytes to the parameter since I need to keep a reference to the same session.
I was able to pass the id from the session as a parameter to my worker, but I couldn't figure out how to find the reference back to the session through this id.
It's possible something could be done with FutureValue here: https://github.com/GoogleCloudPlatform/appengine-pipelines/tree/master/java/src/main/java/com/google/appengine/tools/pipeline
but I'm completely lost on how it's used.
Saving http sessions per user in a HashMap / datastore seems like bad practice since the user might not want to keep the data.
So, any ideas on how to send an asynchronous message back to the user that initiated the task upon task completion/failure?
We implemented our own session system on top of appengine but I believe what we did would work the same for you. Save the start of the job in an entity in the datastore linked up to the session id of the user. Make sure to timestamp it and then use polling on your client side to check if the job has been finished. Update the job's status when it is complete and then purge the entity when you next poll for the status update. To clean up the data that sticks around if the user closes the session just use a appengine cron job to go through and clean up the old entities after a set time.
This has worked well for our implementation and it is a bit more work but that's what you are dealing with when your tasks are async.

Creating Amazon SNS messages to be processed in the future

For the last few years we have used our own RM Application to process events related to our applications. This works by polling a database table every few minutes, looking for any rows that have a due date before now, and have not been processed yet.
We are currently making the transition to SNS, with SQS Worker tiers processing them. The problem with this approach is that we can't future date our messages. Our applications sometimes have events that we don't want to process until a week later.
Are there any design approaches, alternative services, clever tricks we could employ that would allow us to do achieve this?
One solution would be to keep our existing application running, at a simplified level, so all it does is send the SNS notifications when they are due, but the aim of this project is to try and do away with our existing app.
The database approach would be the wisest, being careful that each row is only processed once.
Amazon Simple Notification Service (SNS) is designed to send notifications immediately. There is no functionality for a delayed send (although some notification types are retried if they fail).
Amazon Simple Queue Service (SQS) does have a delay feature, but only up to 15 minutes -- this is useful if you need to do some work before the message is processed, such as copying related data to Amazon S3.
Given that your requirement is to wait until some future arbitrary time (effectively like a scheduling system), you could either start a process and tell it to sleep for a certain amount of time (a bad idea in case systems are restarted), or continue your approach of polling from a database.
If all jobs are scheduled for a distant future (eg at least one hour away), you theoretically only need to poll the database once an hour to retrieve the earliest scheduled time.
A week might be too long as SQS message retention itself is only 15 days. If you are okay with maximum retention of 15days, one idea is to keep the changing the visibility of a message every time you receive until it is ready for processing. The maximum allowed visibility timeout is 12 hours. More on visibility timeout and APIs for changing them,
http://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_ChangeMessageVisibility.html
http://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/AboutVT.html
I found this approach: https://github.com/alestic/aws-sns-delayed. Basically, you can use a step function with a wait step in there

Schedule Tasks in AppEngine

I use appengine (java) as a backend for a mobile app (android). The user of my app can create public events consisting of a title and a date/time. Those events are stored on my appengine backend. Any user can subscribe for events and will receive a push notification at that time the events starts.
So I want to schedule a job / task on appengine to run at the events date/time to send a push notification to all subscribers.
Example:
User A creates an event that will start on Saturday next week on 8 pm. User B and User B subscribe for this event.
On Saturday 8 pm a job/task should start to send the push notifications to User B and User C to inform that the event has started.
My question is:
How do I implement something like this in an efficient way on appengine? I want to say, start a Task for the Event on Saturday at 8 pm. There are Cronjobs and TaskQueues. Cronjobs can not be created programmatically. TaskQueue needs to be pulled and can not be scheduled to pull at a given date / time, right?
So the only solutions I see is to create a cronjob that will run every minute to check if there is a Event that starts right now.
An event can be created at any time and any day in the week. However the most events are created for the weekend and There are days when no event has been created for. So running a cronjob periodically ever minute is very inefficient. Im looking for a smarter solution, any ideas?
Indeed, based on your description, the solution is to create a cron job that checks for new events that start right now.
However, you should be careful not to exceed the 60 second window you have for each cron job. If you have a lot of events, you probably should move the actual processing from the cron job to background tasks using Push Task Queues.
You may take a look to this post for a combination of cron jobs and Task Queues.

Generate reports in background and by schedule using Spring

There are 2 ways user can generate a report.
User click a button on the front end and job will run to generate the report.
User can schedule the report to generate weekly, monthly, etc.
On scenario 1, I decided to first save the request to a table, say "REQUEST_TBL". Right after that, I will run ThreadPoolTaskExecutor which picks up the specific request from "REQUEST_TBL". There could be a lot of users that can request to generate a report. But each user is given only up to 30 reports to generate for life (if user wants to generate a new report, he needs to delete any old reports).
On scenario 2, user can schedule a certain report to generate weekly, or monthly. Then a weekly (or monthly or etc) job will run and generate this report that the user scheduled.
Now, I am not sure on how to implement the report generator job. Whether I use ThreadPoolTaskExecutor or not. Or use the same program to handle user request and user scheduled request for report.
I am planning to let one job to run every minute to read "REQUEST_TBL" and for each record I will run ThreadPoolTaskExecutor.execute(). But if there are 1000 users all the same time they requested report, then how should I implement the creation of thread. Also for the scheduled job, I am planning to run it endofday only. The scheduled job will read from the same "REQUEST_TBL" and look for request that is scheduled. For scenario 1, if I want to run a job for every, say, 2 minutes, until what time should I run it? Cause it may be that at the end of that day, a scheduled report will need to run. Also, I thought of running a job for every, say 2 minutes, because if the server went down, there's no way to regenerate the report once the server is started.
I would appreciate your suggestion
You are asking many question at once. So few thoughts here:
definitely don't create thread yoursels. Use rather one of the Executors and limit the number of threads in this way.
for the rest I'll do it in the most consistent way: every record in REQUEST_TBL will also have time when it needs to be generated. So in scenario 1 you will save current time together with the request. With the scenario 2 you'll create a record(s) with timestamp which is week (months) ahead.
then you can run a job every minute or two to query requests with request time before or equal now. And schedule a job to the executor for each returned record.

Categories

Resources