In my spring boot Application, I have a scheduled task to be daily executed, I am also using two global variables to make sure the work has been done correctly; so the code is like this:
#Service
#EnableScheduling
public class DailyService {
static long sleep=0; // will be used in sleep()
static boolean done=false; //only turns true when the task is correctly complited
#Scheduled(cron = "0 0 1 * * *")//every 01:00:00
void daily() throws InterruptedException
{
do
{
Thread.sleep(sleep); //0 ms if last execution was ok else 30mins
System.out.println(daily());// OK or ERROR
System.out.println(done + " from daily()");//done is the boolean :)
} while(!done);
}
public String process() throws InterruptedException{ //InterruptedException required for sleep()
try {
//some work download file using RestTemplate
work();
sleep=0;
done=true;
System.out.println(done+ " from process()");
return "OK";
}catch (Exception e){
System.out.println(e.getMessage());
sleep =30*60*1000;//30min to wait before the next execution
done=false;
return "ERROR";
}
}
}
as a result process() keeps executing infinitely and in terminal I have an infinity of:
OK
false from daily()
with no "true from process()" ! and done never turned true even if everything is ok!
what is wrong in this code? and how should it be done?
Related
I'm using Java+TestNG+Allure. I need to get all test fails in Allure report, not only the first fail of the test but all, and the test should run from the beginning to the end despite failed steps.
For reporting the test failures in Allure report we have to do little bit of modifications in Allure Class. Here we want to report any of the sub step as a failure, execute the remaining steps and then mark the main test step as a failed test. For doing this we can use the concept of SoftAssertions. I had created one class called as AllureLogger. Inside the class we will have 5 Methods.
1)starttest() 2)endtest() 3) markStepAsPassed(String message) 4)marstepAsFailed(String message) 5)logStep().
public class AllureLogger {
public static Logger log = Logger.getLogger("devpinoylog");
private static StepResult result_fail;
private static StepResult result_pass;
private static String uuid;
private static SoftAssert softAssertion;
public static void startTest() {
softAssertion = new SoftAssert();
}
public static void logStep(String discription) {
log.info(discription);
uuid = UUID.randomUUID().toString();
result_fail = new StepResult().withName(discription).withStatus(Status.FAILED);
result_pass = new StepResult().withName(discription).withStatus(Status.PASSED);
}
public static void markStepAsFailed(WebDriver driver, String errorMessage) {
log.fatal(errorMessage);
Allure.getLifecycle().startStep(uuid, result_fail);
Allure.getLifecycle().addAttachment(errorMessage, "image", "JPEG", ((TakesScreenshot) driver).getScreenshotAs(OutputType.BYTES));
Allure.getLifecycle().stopStep(uuid);
softAssertion.fail(errorMessage);
}
public static void markStepAsPassed(WebDriver driver, String message) {
log.info(message);
Allure.getLifecycle().startStep(uuid, result_pass);
Allure.getLifecycle().stopStep(uuid);
}
public static void endTest() {
softAssertion.assertAll();
softAssertion = null;
startTest();
softAssertion = new SoftAssert();
}
}
In the above class, we are using different methods from allureClass and we are doing little bit of modification to add soft assertions.
Everytime we start a TestMethod in testClass we can call the starttest() and end testmethod().Inside the test methods if we have some substeps we can use try catch block to mark the substeps as pass or fail.Ex-Please check the below test method as an Example
#Test(description = "Login to application and navigate to Applications tab ")
public void testLogin()
{
AllureLogger.startTest();
userLogin();
navigatetoapplicationsTab();
AllureLogger.endTest();
}
Above is a test method which will login to one application and then navigate to application tab.Inside we have two methods which will be reported as substeps, 1)login()- For logging in the application 2) navigatetoapplicationsTab()-to navigate to application tab. If any of the substep fails then the main step and substep will be marked as fail and remaining steps will be executed.
We will define the body of the above functions which are defined in test method as below:
userLogin()
{
AllureLogger.logStep("Login to the application");
try
{
/*
Write the logic here
*/
AllureLogger.MarStepAsPassed(driver,"Login successful");
}
catch(Exception e)
{
AllureLogger.MarStepAsFailed(driver,"Login not successful");
}
}
navigatetoapplicationsTab()
{
AllureLogger.logStep("Navigate to application Tab");
try
{
/*
Write the logic here
*/
AllureLogger.MarStepAsPassed(driver,"Navigate to application Tab successful");
}
catch(Exception e)
{
e.printStackTrace();
AllureLogger.MarStepAsFailed(driver,"Navigate to application Tab failed");
}
}
Everytime any exception is thrown they will be caught in catch block and reported in the Allure Report. The soft assertion enables us to execute all the remaining steps successfully.
Attached is a screenshot of an Allure report generated by using the above technique.The main step is marked as Failed and remaining test cases have got executed.
The report attached here is not from the above example which is mentioned. It is just a sample as how the report would look.
Using Retrofit2 (Ver: 2.3.0), OkHTTP3 (Ver: 3.9.0) with RxJava2 (Ver: 2.0.0)
Scenario of a rest api call
Observable<ServerResponse> backendService.isUserVerified("someuserName")
which returns a 200 Ok HTTP
Expected Success Response JSON POJO if user is verified
{
user: "someUserName",
isVerified: "yes"
}
Expected Success Response JSON POJO if user is not verified
{
user: "someUserName",
isVerified: "no"
}
Following is code I am trying to implement
backendService.isUserVerified("someuserName")
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
//Want to add a flatmap (or some other operator)
.flatmap(new Function<ServerResponse>, ObservableSource<?>>(){
#Override
public ObservableSource<?> apply(ServerResponse serverResponse) throws Exception {
if(0 != serverResponse.getisVerified.compareToIgnoreCase("yes")) {
return Observable.error(new CustomException());
}
return //current observable.
}
.retryWhen(mRetryHandler)
.subscribeWith(observer);
The intent is to throw a custom exception if verified == no so that retryWhen() operator can pitch in to repeat the call chain, else want to proceed through the chain till subscribe().
Any pointers / help ?
You can just use doOnNext rather than flatmap:
backendService.isUserVerified("someuserName")
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
//we can throw an exception if the user is not verified or keep the response as it is otherwise
.doOnNext(serverResponse -> {
if(0 != serverResponse.getisVerified.compareToIgnoreCase("yes"))
{
throw new CustomException();
}
})
.retryWhen(mRetryHandler)
.subscribeWith(observer);
The doOnNext operator just performs a function with the emitted item without changing it. You just want to throw an error in a specific case based on the item and otherwise not to change it so it's an appropriate operator to use. As you don't change threads before the doOnNext operator or after it, before using the item in the next operator you know it will throw the exception BEFORE continuing in case it should throw it.
Here's an example from the linked documentation of the operator:
Observable.just(1, 2, 3)
.doOnNext(new Action1<Integer>() {
#Override
public void call(Integer item) {
if( item > 1 ) {
throw new RuntimeException( "Item exceeds maximum value" );
}
}
}).subscribe(new Subscriber<Integer>() {
#Override
public void onNext(Integer item) {
System.out.println("Next: " + item);
}
#Override
public void onError(Throwable error) {
System.err.println("Error: " + error.getMessage());
}
#Override
public void onCompleted() {
System.out.println("Sequence complete.");
}
});
[output:]
Next: 1
Error: Item exceeds maximum value
If you want to throw an error using Observable.error(new CustomException());, you don't need to make function to return a specific object for the error and another one for the expected answer, it's an exception and will go to onError() method. Your ObservableResource<?> must return your expected answer that is retrieved in onResponse() method from Subscriber. If you throw an error using Observable.error(), your chain will be broken and error will be go to onError().
Edit
You should use retry function, because will return you ServerResponse and you can check if is valid or not. Using retryWhen, you get only the error when something goes wrong. In your case, you don't get any error, you get the answer. In this case, you don't need that flatMap
.retry(new BiPredicate<ServerResponse, Throwable>() {
#Override
public boolean test(ServerResponse serverResponse, Throwable throwable) throws Exception {
return serverResponse.getisVerified.equals("no");
}
})
I'm trying to learn Threads and Tasks for days now ... but still can't implement it in my app ... help plz.
I want to run all Database operations in a background thread other than the application thread.
I have a class that manages the Database queries ... in this class i surrounded the executeQuery statement with a task:
public class Database {
ResultSet rs;
public ResultSet execQuery(PreparedStatement stmnt) throws SQLException {
Task<ResultSet> task = new Task<ResultSet>() {
#Override protected ResultSet call() throws Exception {
if (isCancelled()) {
}
ResultSet execRs = stmnt.executeQuery();
return execRs;
}
};
task.run();
task.setOnSucceeded(new EventHandler<WorkerStateEvent>(){
#Override
public void handle(WorkerStateEvent event) {
rs = task.getValue();
}
});
return rs;
}
// remaining Code
}
As you can see the method should return a ResultSet but when i call this from another place it raise a null pointer ... the result set returned by this method is null.
So what did i do wrong here?
Update #1
#James_D Thank you for this great link ... i think i finally understand the concept ... but still have a small problem with implementing it ... for example in my authentication method after the user is authenticated i want to check if that user has an open shift ... so following your link i changed the method to this:
private boolean isShiftOpen(int userId, int branchId, int comId) throws SQLException, ClassNotFoundException {
// final boolean success = false;
Task<Shift> task = new Task<Shift>(){
#Override
protected Shift call() throws Exception {
return ShiftDAO.getShift(userId, branchId, comId);
}
};
task.setOnFailed(e -> {
System.out.println("isShiftOpenTask Faild!!");
success = false;
});
task.setOnSucceeded(e -> {
System.out.println("isShiftOpenTask Succeeded!!");
Shift shift1 = task.getValue();
System.out.println("User Open Shift Exists ... returning true");
SessionBean.setShiftId(shift1.getShiftId());
SessionBean.setUserId(shift1.getUserId());
SessionBean.setUserBranch(branchId);
success = true;
});
exec.execute(task);
return success;
}
I have two problems:
1- The exec.execute(task) raise a nullpoint exception.
2- I wanted to use a boolean variable returned by this method ... the only way i could access such a variable is to define it outside the method ... but then if i want to use another method like this one i must declare another boolean variable for it to ... does this sound right to you?
Thank you for your time
Gado
You call
task.run();
which executes the task on the current thread, i.e. that statement will not complete until the task finishes. Then you call
task.setOnSucceeded(...);
which essentially says "when the task succeeds, set the instance variable rs to the result of the task. However, by the time you call this, the task has already succeeded (or possibly failed), so there is no way for the handler to be invoked.
You could fix the null result by reversing the order of these calls, i.e. do
public ResultSet execQuery(PreparedStatement stmnt) throws SQLException {
Task<ResultSet> task = new Task<ResultSet>() {
#Override protected ResultSet call() throws Exception {
if (isCancelled()) {
}
ResultSet execRs = stmnt.executeQuery();
return execRs;
}
};
task.setOnSucceeded(new EventHandler<WorkerStateEvent>(){
#Override
public void handle(WorkerStateEvent event) {
rs = task.getValue();
}
});
task.run();
return rs;
}
However, since you are executing the task on the current thread, it's not really clear what the point of using a task at all is: you may as well just execute the database query directly in your execQuery method and return the result directly. In other words, the above code is equivalent to
public ResultSet execQuery(PreparedStatement stmnt) throws SQLException {
rs = stmnt.executeQuery();
return rs;
}
I wrote a little code to download some files from internet..if user click on cancel button this must be stopped..i use the cancel() method for do it..but it didn't work.
ScheduledService<Object> service = new ScheduledService<Object>() {
protected Task<Object> createTask() {
return new Task<Object>() {
protected Object call() {
if (checkinternet()) {
downloadFiles();
}
return null;
}
};
}
};
service.start();
In buttons action event handler i called cancel method for stop service..
but it wasn't successful..
service.cancel();
How do i do that...
There is no automatic way to cancel a task or service.
From the documentation (https://docs.oracle.com/javase/8/javafx/interoperability-tutorial/concurrency.htm):
Cancelling the Task.
There is no reliable way in Java to stop a thread in process. However, the task must stop processing whenever cancel is called on the task. The task is supposed to check periodically during its work whether it was cancelled by using the isCancelled method within the body of the call method.
The example referenced in the above block looks like this:
Task<Integer> task = new Task<Integer>() {
#Override protected Integer call() throws Exception {
int iterations;
for (iterations = 0; iterations < 100000; iterations++) {
if (isCancelled()) {
break;
}
System.out.println("Iteration " + iterations);
}
return iterations;
}
};
So you will have to implement the cancel logic by yourself, unfortunately.
I am new to Windows Workflow and trying to write a Long Running process.
I am also trying to limit how long this process can run for.
I am calling WorkflowInvoker.Invoke to trigger my Workflow passing it a small timespan for testing.
If I try this certain activities, this seems to work perfectly.
But If I use a CodeActivity, it seems to ignore my timeout entirely.
Why is this? And how do I cause my CodeActivity to timeout if it takes too long?
An example working with a Delay Activity:
(In this example the TimeOutException is thrown)
Activity wf = new Sequence()
{
Activities =
{
new Delay()
{
Duration = TimeSpan.FromSeconds(10)
},
}
};
try
{
WorkflowInvoker.Invoke(wf, TimeSpan.FromSeconds(5));
}
catch (TimeoutException ex)
{
Console.WriteLine(ex.Message);
}
An example trying to use a CodeActivity:
(In this example the TimeOutException is not thrown)
public class LongActivity : CodeActivity
{
protected override void Execute(CodeActivityContext context)
{
Thread.Sleep(TimeSpan.FromSeconds(10));
}
}
Activity wf = new Sequence()
{
Activities =
{
new LongActivity()
}
};
try
{
WorkflowInvoker.Invoke(wf, TimeSpan.FromSeconds(5));
}
catch (TimeoutException ex)
{
Console.WriteLine(ex.Message);
}
The workflow runtime can only take action when it is in charge and if your activity takes 10 seconds to execute, or sleep, the runtime can't do anything about it. It won't schedule any new activities though because there is no remaining time left and would throw a TimeoutException instead.
Normally when you have long running work you would use an asynchronous activity, either an AsyncCodeActivity or a NativeActivity with a bookmark so the runtime is in control and can abort the workflow.