Creating workers in Spring - java

I'm writing a webserver with spring(mvc,data,security) which is serving tasks to physical devices(device count is around 100).
Device doesn't have query implementation inside. For example to execute some task u need write something like this:
Device driver = new DeviceDriver();
driver.setSettings(settingsJson);
driver.open(); // noone else can't connect to this device, open() can take up to 1 second
driver.setTask(taskJson);
driver.processTask(); // each task takes a few seconds to execute
String results = driver.getResults();
driver.close();
I'm not really an expert in designing architecture, so for now implemented webserver like this:
TaskController(#RestController) - processing incoming Post requests with tasks and persisting them to database.
DeviceService(#Service) - has init method, which gets list of devices from DB and creates/starts one worker per device. It passes taskRepository to each worker, so worker inside can save results of tasks.
Worker - extends Thread, it gets next task from database with certain period(via loop with sleep). When task executed worker saves result to db and updates status of task.
Does this approach makes any sense? Maybe there is better way to do this using spring components instead of Thread.

I would not create workers for each device (client). Because your controller will be able to serve concurrent requests being deployed on a thread-per-request based server. Additionally, this is not scalable at all- what if there is a new device on-boarded? You need to make changes on the database, restart the service with the current design!!
If you need device specific actions, you can just pass that on the request parameters from the device client. Therefore, there is no need to keep a predefined set of workers.
So, the design looks good except the worker set.

Use the #Scheduled annotation on your functions to build something like cron

Related

Should I create executor service for each request in spring controller?

I am trying to build a rest API controller which takes a list of hostnames as input and a command to be executed in each hostname
#RequestMapping("/tasks")
public Result execute(#RequestParam(value="hostList") List<HostName> hosts, String command) {
//1. Execute the command in each hostname asynchronously and get completable future.
//2. Get a list of completable future for each hostname command execution
//3. Wait for them to complete and then compose the result
}
The question is that, step 1 needs to happen asynchronously for each hostname.
I am planning to create a an executor service (with thread pool size of hosts.size()) for each request and then execute step 1 in that thread pool.
But I think it is a bad idea to create executor for each request, since that will consume a lot of memory.
Is this correct way forward or is there something in built in spring to take care of this scenario.
Please note that the list of hosts can vary from 1 to 20
No, there is no reason to create a new executor for each request. You should have one executor and when your request comes your code should create a number of runnable tasks and submit them to the executor. Also in your case, since you are talking about running some command on different hosts, it means that you don't run any command on your server. You somehow send a message to the relevant host with command to execute. (I assume through a queue). So your commands can NOT be executed synchronously even if you wanted to, since each command is executed on a different host. So, obviously they can not be running in the same process, let alone the same thread. So in your case, you probably don't need to have any Executor at all.
There is no reason to be making a new Thread for each request. You can either have a thread pool with fixed size N created by an Executor or submit your tasks on the Tomcat/any other provider threads that are used to fulfil your HTTP request. I gave two solutions below that may apply to one of your use cases
Below Solution is for when you want the client to wait for their commands to be submitted to their host
You should send a message to your hosts to execute the commands (maybe through a REST API or anything else), and wait for these tasks to either be executed or to be submitted: this all depends on your use case.
Below Solution is for when you want to be able to queue your commands
You can submit tasks to the created Thread Pool which will execute your tasks in an FI-FO order.
Depending on your use case, you can either use 1 or multiple (not too many Threads as this may only degrade your overall performance) threads in your Thread Pool. These tasks will then be executed when picked from the queue.

How can I ensure that my Android app doesn't access a file simultaneously?

I am building a fitness app which continually logs activity on the device. I need to log quite often, but I also don't want to unnecessarily drain the battery of my users which is why I am thinking about batching network calls together and transmitting them all at once as soon as the radio is active, the device is connected to a WiFi or it is charging.
I am using a filesystem based approach to implement that. I persist the data first to a File - eventually I might use Tape from Square to do that - but here is where I encounter the first issues.
I am continually writing new log data to the File, but I also need to periodically send all the logged data to my backend. When that happens I delete the contents of the File. The problem now is how can I prevent both of those operations from happening at the same time? Of course it will cause problems if I try to write log data to the File at the same time as some other process is reading from the File and trying to delete its contents.
I am thinking about using an IntentService essentially act as a queue for all those operations. And since - at least I have read as much - an IntentServices handles Intents sequentially in single worker Thread it shouldn't be possible for two of those operations to happen at the same time, right?
Currently I want to schedule a PeriodicTask with the GcmNetworkManager which would take care of sending the data to the server. Is there any better way to do all this?
1) You are overthinking this whole thing!
Your approach is way more complicated than it has to be! And for some reason none of the other answers point this out, but GcmNetworkManager already does everything you are trying to implement! You don't need to implement anything yourself.
2) Optimal way to implement what you are trying to do.
You don't seem to be aware that GcmNetworkManager already batches calls in the most battery efficient way with automatic retries etc and it also persists the tasks across device boots and can ensure their execution as soon as is battery efficient and required by your app.
Just whenever you have data to save schedule a OneOffTask like this:
final OneoffTask task = new OneoffTask.Builder()
// The Service which executes the task.
.setService(MyTaskService.class)
// A tag which identifies the task
.setTag(TASK_TAG)
// Sets a time frame for the execution of this task in seconds.
// This specifically means that the task can either be
// executed right now, or must have executed at the lastest in one hour.
.setExecutionWindow(0L, 3600L)
// Task is persisted on the disk, even across boots
.setPersisted(true)
// Unmetered connection required for task
.setRequiredNetwork(Task.NETWORK_STATE_UNMETERED)
// Attach data to the task in the form of a Bundle
.setExtras(dataBundle)
// If you set this to true and this task already exists
// (just depends on the tag set above) then the old task
// will be overwritten with this one.
.setUpdateCurrent(true)
// Sets if this task should only be executed when the device is charging
.setRequiresCharging(false)
.build();
mGcmNetworkManager.schedule(task);
This will do everything you want:
The Task will be persisted on the disk
The Task will be executed in a batched and battery efficient way, preferably over Wifi
You will have configurable automatic retries with a battery efficient backoff pattern
The Task will be executed within a time window you can specify.
I suggest for starters you read this to learn more about the GcmNetworkManager.
So to summarize:
All you really need to do is implement your network calls in a Service extending GcmTaskService and later whenever you need to perform such a network call you schedule a OneOffTask and everything else will be taken care of for you!
Of course you don't need to call each and every setter of the OneOffTask.Builder like I do above - I just did that to show you all the options you have. In most cases scheduling a task would just look like this:
mGcmNetworkManager.schedule(new OneoffTask.Builder()
.setService(MyTaskService.class)
.setTag(TASK_TAG)
.setExecutionWindow(0L, 300L)
.setPersisted(true)
.setExtras(bundle)
.build());
And if you put that in a helper method or even better create factory methods for all the different tasks you need to do than everything you were trying to do should just boil down to a few lines of code!
And by the way: Yes, an IntentService handles every Intent one after another sequentially in a single worker Thread. You can look at the relevant implementation here. It's actually very simple and quite straight forward.
All UI and Service methods are by default invoked on the same main thread. Unless you explicitly create threads or use AsyncTask there is no concurrency in an Android application per se.
This means that all intents, alarms, broad-casts are by default handled on the main thread.
Also note that doing I/O and/or network requests may be forbidden on the main thread (depending on Android version, see e.g. How to fix android.os.NetworkOnMainThreadException?).
Using AsyncTask or creating your own threads will bring you to concurrency problems but they are the same as with any multi-threaded programming, there is nothing special to Android there.
One more point to consider when doing concurrency is that background threads need to hold a WakeLock or the CPU may go to sleep.
Just some idea.
You may try to make use of serial executor for your file, therefore, only one thread can be execute at a time.
http://developer.android.com/reference/android/os/AsyncTask.html#SERIAL_EXECUTOR

Persisting handles of tasks scheduled by ManagedScheduledExecutorService

This is related to the Timer Service:
To save a Timer object for future reference, invoke its getHandle
method and store the TimerHandle object in a database. (A TimerHandle
object is serializable.) To reinstantiate the Timer object, retrieve
the handle from the database and invoke getTimer on the handle. A
TimerHandle object cannot be passed as an argument of a method defined
in a remote or web service interface. In other words, remote clients
and web service clients cannot access a bean’s TimerHandle object.
Local clients, however, do not have this restriction.
I'd like to know if it is somehow possible to do something similar with tasks scheduled by the ManagedScheduledExecutorService.
What I'd like to implement:
I'm working on a web app that displays different reports (e.g. tables, charts etc.) based on corporate data. The user is able to export a specific report to pdf.
Now, I'd like to give the user the possibility to subscribe to a specific report, meaning he wants to get that report mailed weekly, monthly, or to whatever time he configures while subscribing. Of course, also unsubscribing should be possible at any time, and for this I think I need to refer to some persisted user-related task information (like the handler in the Timer Service) that leads me to the task to be canceled.
The reason why I'm opting for the Executor Service is - as far as I've investigated on - that it is better suited for concurrent batch jobs. The Timer Service schedules all the tasks on a single thread, which might lead to blocking tasks.

What's the effect on a second request of calling Thread.currentThread().sleep(2000) in a Spring MVC request handler?

I need to wait for a condition in a Spring MVC request handler while I call a third party service to update some entities for a user.
The wait averages about 2 seconds.
I'm calling Thread.sleep to allow the remote call to complete and for the entities to be updated in the database:
Thread.currentThread().sleep(2000);
After this, I retrieve the updated models from the database and display the view.
However, what will be the effect on parallel requests that arrive for processing at this controller/request handler?
Will parallel requests also experience a wait?
Or will they be spawned off into separate threads and so not be affected by the delay experienced by the current request?
What are doing may work sometimes, but it is not a reliable solution.
The Java Future interface, along with a configured ExecutorService allows you to begin some operation and have one or more threads wait until the result is ready (or optionally until a certain amount of time has passed).
You can find documentation for it here:
http://download.oracle.com/javase/6/docs/api/java/util/concurrent/Future.html

How to design a system that queues requests & processes them in batches?

I have at my disposal a REST service that accepts a JSON array of image urls, and will return scaled thumbnails.
Problem
I want to batch up image URLs sent by concurrent clients before calling the REST service.
Obviously if I receive 1 image, I should wait a moment in case other images trickle in.
I've settled on a batch of 5 images. But the question is, how do I design it to take care of these scenarios:
If I receive x images, such that x < 5, how do I timeout from waiting if no new images will arrive in the next few minutes.
If I use a queue to buffer incoming image urls, I will probably need to lock it to prevent clients from concurrently writing while I'm busy reading my batches of 5. What data structure is good for this ? BlockingQueue ?
The data structure is not what's missing. What's missing is an entity - a Timer task, I'd say, which you stop and restart every time you send a batch of images to your service. You do this whether you send them because you had 5 (incidentally, I assume that 5 is just your starting number and it'll be configurable, along with your timeout), or whether because the timeout task fired.
So there's two entities running: a main thread which receives requests, queues them, checks queue depth, and if it's 5 or more, sends the oldest 5 to the service (and restarts the timer task); and the timer task, which picks up incomplete batches and sends them on.
Side note: that main thread seems to have several responsibilities, so some decomposition might be in order.
Well what you could do is have the clients send a special string to the queue, indicating that it is done sending image URLs. So if your last element in the queue is that string, you know that there are no URLs left.
If you have multiple clients and you know the number of clients you can always count the amount of the indicators in the queue to check if all of the clients are finished.
1- As example, if your Java web app is running on Google AppEngine, you could write each client request in the datastore, have cron job (i.e. scheduled task in GAE speak) read the datastore, build a batch and send it.
2- For the concurrency/locking aspect, then again you could rely on GAE datastore to provide atomicity.
Of course feel free to disregard my proposal if GAE isn't an option.

Categories

Resources