I have a Java application that runs several scheduler to get and provide data to an external application. I will have to add another scheduler to get data from another external application. That would be the exact same process as one of the scheduler already existing for the first application.
So roughly it would be something like this:
However I have small confidence in the formatting of the data of this second application, I know that they have less verifications that the fist application and I might get funny things. I will obviously put plenty of null/bad format check on my side, but I have to make sure that if they ever send me bad data this doesn't impact my others schedulers.
#EnableScheduling
public class myApp{
#Scheduled(fixedRate = 1000)
public void externalApp1() {
do stuff...
commonMethod();
}
#Scheduled(fixedRate = 1000)
public void externalApp2() {
do stuff...
commonMethod();
}
public void commonMethod(){
doStuff...
}
}
One of my first idea is to put dedicated threads to each scheduler, so that if they send bad data and it ends up killing the thread for whatever reason, it only impacts their own process and not the schedulers for the first external application. I have done this for now based on what I found, I suppose this should work as intended:
#Configuration
#EnableAsync
#EnableScheduling
public class MyApp{
#Scheduled(fixedRate = 1000)
#Async(value = "threadPool1")
public void externalApp1() {
dostuff...
commonMethod();
}
#Scheduled(fixedRate = 1000)
#Async(value = "threadPool2")
public void externalApp2() {
dostuff...
commonMethod();
}
public void commonMethod(){
doStuff...
}
#Bean
public Executor threadPool1() {
return Executors.newFixedThreadPool(1);
}
#Bean
public Executor threadPool2() {
return Executors.newFixedThreadPool(1);
}
}
(actual code would be with beans properly separated from main class)
But I am wondering if there is any other way to fully ensure the processes are totally independant from one another?
EDIT: I precise that the data I get from the second application are not used for any process of the first application. It has a process on its own and data are not shared between those 2 external applications
Related
I'm writing REST API of coupons system,
and I'm trying to create a thread that works all the time that the server is running.
The thread needs to remove the token+client session if the client doesn't use the server (through the controllers class) passes 10 seconds.
The class of the thread:
public class ClientSessionCleaner implements Runnable {
private boolean run = true;
private Map<String, ClientSession> tokensMap;
public ClientSessionCleaner() {
/*Empty*/
}
#Autowired
public ClientSessionCleaner(#Qualifier("tokens") Map<String, ClientSession> tokensMap) {
this.tokensMap = tokensMap;
}
#Override
public void run() {
HashMap<String, ClientSession> copy = new HashMap<>(tokensMap);
do {
CleanMap(copy);
}while (run);
}
private void CleanMap(HashMap<String, ClientSession> copy) {
copy.forEach((k, v) -> {
if (System.currentTimeMillis() - v.getLastAccessMillis() == 10 * 1_000){
copy.remove(k);
}
});
}
I'm starting the thread in the main class, it is ok?
public static void main(String[] args) {
SpringApplication.run(CouponSystemApplication.class, args);
ClientSessionCleaner cleaner = new ClientSessionCleaner();
Thread thread =new Thread(cleaner);
thread.start();
}
When I'm starting the server I'm getting this:
Exception in thread "Thread-178" java.lang.NullPointerException
at java.base/java.util.HashMap.putMapEntries(HashMap.java:496)
at java.base/java.util.HashMap.<init>(HashMap.java:485)
at com.Avinadav.couponsystem.rest.login.ClientSessionCleaner.run(ClientSessionCleaner.java:25)
at java.base/java.lang.Thread.run(Thread.java:834)
The tokens map:
#Configuration
public class RestConfiguration {
#Bean(name = "tokens")
public Map<String, ClientSession> tokensMap() {
return new HashMap<>();
}
}
I don't know if the thread code is ok (?) and what I should do to make the thread work.
I'm new with threads,
thx for all the help!
If I understand you correctly, it seems like you're trying to implement some kind of a cleanup service for outdated ClientSessions. Is that right?
If so, your Runnable can actually be a #Component in which a #Scheduled annotation will define a periodic procedure in which the cleaning will take place.
For more info about Scheduling, check out the The #Scheduled Annotation in Spring
Your use-case may fit the functionality of a popular caching library like Caffeine or Google Guava, because it has support for maps with time-based eviction and it seems to be me that's what you're trying to accomplish.
LoadingCache<String, ClientSession> tokensMap = Caffeine.newBuilder()
.expireAfterAccess(10, TimeUnit.SECONDS)
.build();
For more complex logic use LoadingCache#expireAfter. Using a library like this will prevent you from having to deal with complex concurrency issues.
My application starts couple of clients which communicate with steam. There are two types of task which I can ask for clients. One when I don't care about blocking for example ask client about your friends. But second there are tasks which I can submit just one to client and I need to wait when he finished it asynchronously. So I am not sure if there is already some design pattern but you can see what I already tried. When I ask for second task I removed it from queue and return it here after this task is done. But I don't know if this is good sollution because I can 'lost' some clients when I do something wrong
#Component
public class SteamClientWrapper {
private Queue<DotaClientImpl> clients = new LinkedList<>();
private final Object clientLock = new Object();
public SteamClientWrapper() {
}
#PostConstruct
public void init() {
// starting clients here clients.add();
}
public DotaClientImpl getClient() {
return getClient(false);
}
public DotaClientImpl getClient(boolean freeLast) {
synchronized (clients) {
if (!clients.isEmpty()) {
return freeLast ? clients.poll() : clients.peek();
}
}
return null;
}
public void postClient(DotaClientImpl client) {
if (client == null) {
return;
}
synchronized (clientLock) {
clients.offer(client);
clientLock.notify();
}
}
public void doSomethingBlocking() {
DotaClientImpl client = getClient(true);
client.doSomething();
}
}
Sounds like you could use Spring's ThreadPoolTaskExecutor to do that.
An Executor is basically what you tried to do - store tasks in a queue and process the next as soon the previous has finished.
Often this is used to run tasks in parallel, but it can also reduce overhead for serial processing.
A sample doing it this way would be on
https://dzone.com/articles/spring-and-threads-taskexecutor
To ensure only one client task runs at a time, simply set the configuration to
executor.setCorePoolSize(1);
executor.setMaxPoolSize(1);
My frontend is timing out (504 error) when calling my backend service. This is because my backend service takes ~6 minutes to finish running. I want to return a response to the front-end within a minute and have my backend code continue running after the response is given to the frontend.
I want to use concurrency to run two code segments. One thread will return a String to the frontend, the other thread will call the code that takes around 5 minutes to run on my server.
I want my solution to be simple as this seems like a simple problem to fix, so I am using the simple Executor class from java.util.concurrent
I made my Invoker class as followed:
public class Invoker implements Executor {
#Override
public void execute(Runnable r) {
r.run();
}
}
In my actual code, I have
import java.util.concurrent.Executor;
import com.dcc.standalone.Invoker;
public String aCoolFunction() {
String status = "good job, homie";
Executor executor = new Invoker();
executor.execute( () -> {
// Call this part of the code that takes 5 minutes to run CODE_A
});
return status;
}
I expect status to be returned at the same time CODE_A starts running. Instead, the code runs sequentially as before, i.e., status is returned after CODE_A runs.
maybe use a CompletableFuture?
Setup a ThreadPoolTaskExecutor.
#Configuration
#EnableAsync
public class SpringAsyncConfig {
#Bean(name = "threadPoolTaskExecutor")
public Executor threadPoolTaskExecutor() {
return new ThreadPoolTaskExecutor();
}
}
Define your function
public String aCoolFunction() {
String status = "good job, homie";
someAsyncFunction();
return status;
}
Define a async long running function.
#Async
public void someAsyncFcuntion() {
// Call this part of the code that takes 5 minutes to run CODE_A
}
run your cool function somewhere in a CompletableFuture
String result CompletableFuture.supplyAsync(() -> aCoolFunction()).get();
I'm writing from mobile, but this is what i could come up with from the top of my head.
Declare #Async or create a threadpool using Executors for the service field you want to use. ex)
#Service
public class SimpleService {
private ExectorService pool = Executors.newFixedThreadPool(10);
public String someThing() {
String status = "good job, homie";
pool.execute(() -> {
// other logic
})
return status;
}
}
I am having thoughts on how do I write a test case for this using mockito.
Example, part of my logic in my main thread is to create a thread that does 3 things.
Please see my annotated code below.
Now the RequestThread can be spawn many times depending on the number of inputs coming from the main program.
public class MainThreads {
public static void main(String[] args) {
RequestThread rt = new RequestThread("sample");
rt.start();
//RequestThread another = new RequestThread("sample-2");
//another.start();
//RequestThread newThread = new RequestThread("sample-3");
//newThread.start();
}
public static class RequestThread implements Runnable{
private final String request;
public RequestThread(String request) {
this.request = request;
}
#Override
public void run() {
//1. Instantiate a service passing the required request parameter
MyDataWebService service = new MyDataWebService(request);
//2. Get the returned data
List<String> dataList = service.requestData();
//3. Write to file
Path file = Paths.get("/someDir/" + request);
Files.write(file, dataList, Charset.forName("UTF-8"));
}
}
}
My issue is this, I could not figure out how to properly write a JUnit/Mockito test for a threaded class.
I am not that well verse on Mockito and JUnit in general so I am looking for a way to unit test
a threaded application.
Can somebody guide me on how can I unit test such thing?
You need to bring some changes to your code in order to make it more testing-friendly. In particular:
Objects that you want to mock should implement an interface
Do not instantiate objects to mock in the function that you want to test
Here is a rewrite of the classes so that you can mock MyDataWebService and test RequestThread. Based on this example you will more easily be able to write a full test for the MainThreads class.
public class MainThreads {
public static void main(String[] args) {
RequestThread rt = new RequestThread("sample");
rt.start();
//RequestThread another = new RequestThread("sample-2");
//another.start();
//RequestThread newThread = new RequestThread("sample-3");
//newThread.start();
}
public static class RequestThread extends Thread {
private final String request;
// One important thing to note here, "service" has to be non-final. Else mockito won't be able to inject the mock.
private MyDataWebServiceInterface service;
public RequestThread(String request) {
this.request = request;
//1. Instantiate a service passing the required request parameter
// => do it in constructor, or passed as parameter, but NOT in the function to test
service = new MyDataWebService(request);
}
#Override
public void run() {
//2. Get the returned data
List<String> dataList = service.requestData();
//3. Write to file
Path file = Paths.get("someDir/" + request);
try {
Files.write(file, dataList, Charset.forName("UTF-8"));
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
The interface & implementation for MyDataWebService:
interface MyDataWebServiceInterface {
List<String> requestData();
}
class MyDataWebService implements MyDataWebServiceInterface {
public MyDataWebService(String request) {
}
#Override
public List<String> requestData() {
return Arrays.asList("foo", "bar");
}
}
And a test using mockito. Note, the checks for existing file and thread sleeping may not be the most elegant thing to do here. If you can afford adding some marker in RequestThread to indicate that the data has been written, it would certainly make the test better and safer (filesystems i/o are sometimes tricky to test).
#RunWith(MockitoJUnitRunner.class)
public class RequestThreadTest {
private static final Path FILE = Paths.get("someDir", "sample");
#Mock
MyDataWebServiceInterface service;
#InjectMocks
MainThreads.RequestThread reqThread = new MainThreads.RequestThread("sample");
#Before
public void setup() throws IOException, InterruptedException {
if (Files.exists(FILE)) {
Files.delete(FILE);
while (Files.exists(FILE)) {
Thread.sleep(50);
}
}
}
#Test
public void shouldWriteFile() throws InterruptedException {
Mockito.when(service.requestData()).thenReturn(Arrays.asList("one", "two"));
reqThread.start();
while (!Files.exists(FILE)) {
Thread.sleep(50);
}
// HERE run assertions about file content
}
}
Now, testing asynchronous code is often more complicated than synchronous because you will often face non-determinist behaviours, timing issues, etc. You may want to set a timeout on your test, but remember: continuous integration tools (jenkins, travis etc.) will often run slower than your machine, it's a common cause of problems, so don't set it too tight. As far as I know there is no "one-fits-all" solution for non-determinist issues.
There's an excellent article about non-determinism in tests by Martin Fowler: https://martinfowler.com/articles/nonDeterminism.html
A distinctive non-answer: in 2018, you don't use "raw" threads any more.
Java has much better abstractions to offer by now, for example the ExecutorService. And guess what: when you have your code submit tasks into such a service, you can probably test it using a same-thread executor service.
Meaning: by using such abstractions and dissecting your delivery into specific services, you might be able to (almost) fully test not only the small units, but also how tasks come into your system and worked on.
In other words: you unit test your "tasks", then you "unit" test the integration of tasks when they go into such an executor. Then you are only left with a bit of real function/integration testing to check that the "true parallel" solution behaves as expected.
Anything else gets complicated quickly. Using real threads in ordinary unit tests can lead to inconsistent behavior, or increased runtimes (like the test waiting for threads to asynchronously doing something).
As in your example: your test would simply sit there and regularly check if the expected file was written with the expected content. Leading to: how long should it wait before failing? Waiting not long enough means that your test will occasionally fail because code sometimes just takes longer. If you wait too long, that adds up to the overall time you need to run your tests. You don't want to end up with hundreds of unit tests were some need 10, 20 seconds because "waiting for other threads".
I'm using Spring and I've serveral #Scheduled classes in my application:
#Component
public class CheckHealthTask {
#Scheduled(fixedDelay = 10_000)
public void checkHealth() {
//stuff inside
}
}
#Component
public class ReconnectTask {
#Scheduled(fixedDelay = 1200_000)
public void run() {
//stuff here
}
}
I want the first task use a pool of 2 threads, while the second use a single thread. I don't want the second task is stuck because the first one use all threads available and the computation is slower than fixedDelay time.
Of course mine is just an example to get you the idea.
I could use a configuration class like this:
#Configuration
#EnableScheduling
public class TaskConfig implements SchedulingConfigurer {
#Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(taskScheduler());
}
#Bean
public Executor taskScheduler() {
ThreadPoolTaskScheduler t = new ThreadPoolTaskScheduler();
t.setPoolSize(2);
t.setThreadNamePrefix("taskScheduler - ");
t.initialize();
return t;
}
}
I don't understand how define a different configuration for each #Scheduled component though.
The first task does not require a pool of 2 threads.
Different tasks do not need to be assigned different pools if all using fixed delays. The fixedDelay works as follows:
#Scheduled(fixedDelay=5000)
public void doSomething() {
// something that should execute periodically
}
Would be invoked every 5 seconds with a fixed delay, meaning that the period will be measured from the completion time of each preceding invocation.
Each task only uses one thread, if you have two threads, one thread will not hold up the other to be useable for the other task.